tremble 4 년 전
커밋
a215a35329
100개의 변경된 파일20518개의 추가작업 그리고 0개의 파일을 삭제
  1. 12 0
      .babelrc
  2. 9 0
      .editorconfig
  3. 4 0
      .eslintignore
  4. 29 0
      .eslintrc.js
  5. 14 0
      .gitignore
  6. 10 0
      .postcssrc.js
  7. 21 0
      README.md
  8. 41 0
      build/build.js
  9. 54 0
      build/check-versions.js
  10. BIN
      build/logo.png
  11. 102 0
      build/utils.js
  12. 22 0
      build/vue-loader.conf.js
  13. 96 0
      build/webpack.base.conf.js
  14. 95 0
      build/webpack.dev.conf.js
  15. 145 0
      build/webpack.prod.conf.js
  16. BIN
      code.rar
  17. 7 0
      config/dev.env.js
  18. 75 0
      config/index.js
  19. 4 0
      config/prod.env.js
  20. 17 0
      index.html
  21. 11753 0
      package-lock.json
  22. 85 0
      package.json
  23. 23 0
      src/App.vue
  24. 539 0
      src/assets/font/demo.css
  25. 354 0
      src/assets/font/demo_index.html
  26. 49 0
      src/assets/font/iconfont.css
  27. BIN
      src/assets/font/iconfont.eot
  28. 1 0
      src/assets/font/iconfont.js
  29. 65 0
      src/assets/font/iconfont.json
  30. 50 0
      src/assets/font/iconfont.svg
  31. BIN
      src/assets/font/iconfont.ttf
  32. BIN
      src/assets/font/iconfont.woff
  33. BIN
      src/assets/font/iconfont.woff2
  34. BIN
      src/assets/img/01jk.png
  35. BIN
      src/assets/img/01jks.png
  36. BIN
      src/assets/img/02fb.png
  37. BIN
      src/assets/img/03mg.png
  38. BIN
      src/assets/img/04fb.png
  39. BIN
      src/assets/img/1.png
  40. BIN
      src/assets/img/2.png
  41. BIN
      src/assets/img/4dage-logo.png
  42. BIN
      src/assets/img/bar.png
  43. BIN
      src/assets/img/bg.png
  44. BIN
      src/assets/img/bg1.png
  45. BIN
      src/assets/img/bg2.png
  46. BIN
      src/assets/img/icon.png
  47. BIN
      src/assets/img/icon2.png
  48. BIN
      src/assets/img/icon2s.png
  49. BIN
      src/assets/img/logout.png
  50. BIN
      src/assets/img/noPicture.png
  51. BIN
      src/assets/img/user.png
  52. BIN
      src/assets/img/zhoushan-logo.jpg
  53. 171 0
      src/assets/style/public.css
  54. 109 0
      src/assets/style/reset.css
  55. 281 0
      src/components/cropper/index.vue
  56. 58 0
      src/components/crumbs/index.vue
  57. 97 0
      src/components/focus-bang/index.vue
  58. 94 0
      src/components/hot-bang/index.vue
  59. 50 0
      src/components/info-card/index.vue
  60. 59 0
      src/components/main-top/index.vue
  61. 57 0
      src/components/nums/index.vue
  62. 28 0
      src/components/pie-tu/index.vue
  63. 46 0
      src/components/power-bar/index.vue
  64. 108 0
      src/components/search-bar/index.vue
  65. 35 0
      src/components/trend/index.vue
  66. 58 0
      src/components/ww-card/index.vue
  67. 72 0
      src/configue/base.js
  68. 3 0
      src/configue/bus.js
  69. 84 0
      src/configue/http.js
  70. 251 0
      src/configue/myCharts.js
  71. 40 0
      src/main.js
  72. 239 0
      src/pages/cultural-relic/index.vue
  73. 155 0
      src/pages/cultural-relic/style.css
  74. 294 0
      src/pages/device/index.vue
  75. 106 0
      src/pages/device/style.css
  76. 236 0
      src/pages/display/index.vue
  77. 112 0
      src/pages/display/style.css
  78. 627 0
      src/pages/editPages/cultural-relic/index.vue
  79. 53 0
      src/pages/editPages/cultural-relic/style.less
  80. 442 0
      src/pages/editPages/display/index.vue
  81. 136 0
      src/pages/editPages/display/style.css
  82. 379 0
      src/pages/editPages/message/index.vue
  83. 54 0
      src/pages/editPages/message/style.less
  84. 117 0
      src/pages/editPages/questionnaire/index.vue
  85. 30 0
      src/pages/editPages/questionnaire/style.css
  86. 342 0
      src/pages/editPages/role/index.vue
  87. 84 0
      src/pages/editPages/role/style.less
  88. 446 0
      src/pages/home/index.vue
  89. 185 0
      src/pages/home/style.css
  90. 255 0
      src/pages/information/index.vue
  91. 111 0
      src/pages/information/style.css
  92. 136 0
      src/pages/layout/aside.vue
  93. 47 0
      src/pages/layout/footer.vue
  94. 130 0
      src/pages/layout/head.vue
  95. 55 0
      src/pages/layout/index.vue
  96. 119 0
      src/pages/login/index.vue
  97. 63 0
      src/pages/login/style.css
  98. 89 0
      src/pages/message/index.vue
  99. 99 0
      src/pages/message/style.css
  100. 0 0
      src/pages/modify/index.vue

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

+ 41 - 0
build/build.js

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

+ 54 - 0
build/check-versions.js

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

BIN
build/logo.png


+ 102 - 0
build/utils.js

@@ -0,0 +1,102 @@
+'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',
+        publicPath: '../../'
+      })
+    } 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'
+  }
+}

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

@@ -0,0 +1,96 @@
+'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: /\.less$/,
+        loader: "style-loader!css-loader!less-loader"
+      },
+      {
+        test: /\.js$/,
+        loader: 'babel-loader',
+        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
+      },
+      {
+        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('img/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 100000,
+          name: utils.assetsPath('media/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
+        }
+      }
+    ]
+  },
+  node: {
+    // prevent webpack from injecting useless setImmediate polyfill because Vue
+    // source contains it (although only uses it if it's native).
+    setImmediate: false,
+    // prevent webpack from injecting mocks to Node native modules
+    // that does not make sense for the client
+    dgram: 'empty',
+    fs: 'empty',
+    net: 'empty',
+    tls: 'empty',
+    child_process: 'empty'
+  }
+}

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

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

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

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

BIN
code.rar


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

+ 75 - 0
config/index.js

@@ -0,0 +1,75 @@
+'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: '192.168.0.172', // 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>

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 11753 - 0
package-lock.json


+ 85 - 0
package.json

@@ -0,0 +1,85 @@
+{
+  "name": "szh-system",
+  "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",
+    "echarts": "^4.2.1",
+    "element-ui": "^2.4.9",
+    "js-cookie": "^2.2.0",
+    "less": "^3.9.0",
+    "less-loader": "^5.0.0",
+    "qs": "^6.5.2",
+    "swiper": "^6.2.0",
+    "vue": "^2.5.2",
+    "vue-awesome-swiper": "^4.1.1",
+    "vue-cropper": "^0.5.5",
+    "vue-router": "^3.0.1",
+    "vue2-editor": "^2.10.2",
+    "vuedraggable": "^2.24.0"
+  },
+  "devDependencies": {
+    "autoprefixer": "^7.1.2",
+    "babel-core": "^6.22.1",
+    "babel-eslint": "^8.2.1",
+    "babel-helper-vue-jsx-merge-props": "^2.0.3",
+    "babel-loader": "^7.1.1",
+    "babel-plugin-syntax-jsx": "^6.18.0",
+    "babel-plugin-transform-runtime": "^6.22.0",
+    "babel-plugin-transform-vue-jsx": "^3.5.0",
+    "babel-preset-env": "^1.3.2",
+    "babel-preset-stage-2": "^6.22.0",
+    "chalk": "^2.0.1",
+    "copy-webpack-plugin": "^4.0.1",
+    "css-loader": "^0.28.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",
+    "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",
+    "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"
+  ]
+}

+ 23 - 0
src/App.vue

@@ -0,0 +1,23 @@
+<template>
+  <div id="app">
+    <router-view/>
+  </div>
+</template>
+
+<script>
+import '@/assets/style/reset.css'
+import '@/assets/style/public.css'
+import '@/assets/font/iconfont.css'
+
+export default {
+  name: 'App'
+}
+</script>
+
+<style>
+  #app{
+    width: 100%;
+    height: 100%;
+    background-color: #f0f0f2;
+  }
+</style>

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

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

+ 354 - 0
src/assets/font/demo_index.html

@@ -0,0 +1,354 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8"/>
+  <title>IconFont Demo</title>
+  <link rel="shortcut icon" href="https://gtms04.alicdn.com/tps/i4/TB1_oz6GVXXXXaFXpXXJDFnIXXX-64-64.ico" type="image/x-icon"/>
+  <link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
+  <link rel="stylesheet" href="demo.css">
+  <link rel="stylesheet" href="iconfont.css">
+  <script src="iconfont.js"></script>
+  <!-- jQuery -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
+  <!-- 代码高亮 -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
+</head>
+<body>
+  <div class="main">
+    <h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">&#xe86b;</a></h1>
+    <div class="nav-tabs">
+      <ul id="tabs" class="dib-box">
+        <li class="dib active"><span>Unicode</span></li>
+        <li class="dib"><span>Font class</span></li>
+        <li class="dib"><span>Symbol</span></li>
+      </ul>
+      
+      <a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=1563253" target="_blank" class="nav-more">查看项目</a>
+      
+    </div>
+    <div class="tab-container">
+      <div class="content unicode" style="display: block;">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe699;</span>
+                <div class="name">index</div>
+                <div class="code-name">&amp;#xe699;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe69a;</span>
+                <div class="name">work</div>
+                <div class="code-name">&amp;#xe69a;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe69b;</span>
+                <div class="name">system</div>
+                <div class="code-name">&amp;#xe69b;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe69c;</span>
+                <div class="name">senior</div>
+                <div class="code-name">&amp;#xe69c;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe69d;</span>
+                <div class="name">sys01</div>
+                <div class="code-name">&amp;#xe69d;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe69e;</span>
+                <div class="name">sys02</div>
+                <div class="code-name">&amp;#xe69e;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe69f;</span>
+                <div class="name">sys03</div>
+                <div class="code-name">&amp;#xe69f;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe6a0;</span>
+                <div class="name">arrow</div>
+                <div class="code-name">&amp;#xe6a0;</div>
+              </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="unicode-">Unicode 引用</h2>
+          <hr>
+
+          <p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
+          <ul>
+            <li>兼容性最好,支持 IE6+,及所有现代浏览器。</li>
+            <li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
+            <li>但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。</li>
+          </ul>
+          <blockquote>
+            <p>注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式</p>
+          </blockquote>
+          <p>Unicode 使用步骤如下:</p>
+          <h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
+<pre><code class="language-css"
+>@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.eot');
+  src: url('iconfont.eot?#iefix') format('embedded-opentype'),
+      url('iconfont.woff2') format('woff2'),
+      url('iconfont.woff') format('woff'),
+      url('iconfont.ttf') format('truetype'),
+      url('iconfont.svg#iconfont') format('svg');
+}
+</code></pre>
+          <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
+<pre><code class="language-css"
+>.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
+<pre>
+<code class="language-html"
+>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
+</code></pre>
+          <blockquote>
+            <p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+          </blockquote>
+          </div>
+      </div>
+      <div class="content font-class">
+        <ul class="icon_lists dib-box">
+          
+          <li class="dib">
+            <span class="icon iconfont iconindex"></span>
+            <div class="name">
+              index
+            </div>
+            <div class="code-name">.iconindex
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont iconwork"></span>
+            <div class="name">
+              work
+            </div>
+            <div class="code-name">.iconwork
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont iconsystem"></span>
+            <div class="name">
+              system
+            </div>
+            <div class="code-name">.iconsystem
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont iconsenior"></span>
+            <div class="name">
+              senior
+            </div>
+            <div class="code-name">.iconsenior
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont iconsys"></span>
+            <div class="name">
+              sys01
+            </div>
+            <div class="code-name">.iconsys
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont iconsys1"></span>
+            <div class="name">
+              sys02
+            </div>
+            <div class="code-name">.iconsys1
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont iconsys2"></span>
+            <div class="name">
+              sys03
+            </div>
+            <div class="code-name">.iconsys2
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont iconarrow"></span>
+            <div class="name">
+              arrow
+            </div>
+            <div class="code-name">.iconarrow
+            </div>
+          </li>
+          
+        </ul>
+        <div class="article markdown">
+        <h2 id="font-class-">font-class 引用</h2>
+        <hr>
+
+        <p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
+        <p>与 Unicode 使用方式相比,具有如下特点:</p>
+        <ul>
+          <li>兼容性良好,支持 IE8+,及所有现代浏览器。</li>
+          <li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
+          <li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
+          <li>不过因为本质上还是使用的字体,所以多色图标还是不支持的。</li>
+        </ul>
+        <p>使用步骤如下:</p>
+        <h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
+<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
+</code></pre>
+        <h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;span class="iconfont iconxxx"&gt;&lt;/span&gt;
+</code></pre>
+        <blockquote>
+          <p>"
+            iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+        </blockquote>
+      </div>
+      </div>
+      <div class="content symbol">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#iconindex"></use>
+                </svg>
+                <div class="name">index</div>
+                <div class="code-name">#iconindex</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#iconwork"></use>
+                </svg>
+                <div class="name">work</div>
+                <div class="code-name">#iconwork</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#iconsystem"></use>
+                </svg>
+                <div class="name">system</div>
+                <div class="code-name">#iconsystem</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#iconsenior"></use>
+                </svg>
+                <div class="name">senior</div>
+                <div class="code-name">#iconsenior</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#iconsys"></use>
+                </svg>
+                <div class="name">sys01</div>
+                <div class="code-name">#iconsys</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#iconsys1"></use>
+                </svg>
+                <div class="name">sys02</div>
+                <div class="code-name">#iconsys1</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#iconsys2"></use>
+                </svg>
+                <div class="name">sys03</div>
+                <div class="code-name">#iconsys2</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#iconarrow"></use>
+                </svg>
+                <div class="name">arrow</div>
+                <div class="code-name">#iconarrow</div>
+            </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="symbol-">Symbol 引用</h2>
+          <hr>
+
+          <p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
+            这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
+          <ul>
+            <li>支持多色图标了,不再受单色限制。</li>
+            <li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
+            <li>兼容性较差,支持 IE9+,及现代浏览器。</li>
+            <li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
+          </ul>
+          <p>使用步骤如下:</p>
+          <h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
+<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
+</code></pre>
+          <h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
+<pre><code class="language-html">&lt;style&gt;
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+&lt;/style&gt;
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
+  &lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
+&lt;/svg&gt;
+</code></pre>
+          </div>
+      </div>
+
+    </div>
+  </div>
+  <script>
+  $(document).ready(function () {
+      $('.tab-container .content:first').show()
+
+      $('#tabs li').click(function (e) {
+        var tabContent = $('.tab-container .content')
+        var index = $(this).index()
+
+        if ($(this).hasClass('active')) {
+          return
+        } else {
+          $('#tabs li').removeClass('active')
+          $(this).addClass('active')
+
+          tabContent.hide().eq(index).fadeIn()
+        }
+      })
+    })
+  </script>
+</body>
+</html>

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 49 - 0
src/assets/font/iconfont.css


BIN
src/assets/font/iconfont.eot


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 0
src/assets/font/iconfont.js


+ 65 - 0
src/assets/font/iconfont.json

@@ -0,0 +1,65 @@
+{
+  "id": "1563253",
+  "name": "舟山博物馆de'mo",
+  "font_family": "iconfont",
+  "css_prefix_text": "icon",
+  "description": "",
+  "glyphs": [
+    {
+      "icon_id": "12322900",
+      "name": "index",
+      "font_class": "index",
+      "unicode": "e699",
+      "unicode_decimal": 59033
+    },
+    {
+      "icon_id": "12322902",
+      "name": "work",
+      "font_class": "work",
+      "unicode": "e69a",
+      "unicode_decimal": 59034
+    },
+    {
+      "icon_id": "12322906",
+      "name": "system",
+      "font_class": "system",
+      "unicode": "e69b",
+      "unicode_decimal": 59035
+    },
+    {
+      "icon_id": "12322907",
+      "name": "senior",
+      "font_class": "senior",
+      "unicode": "e69c",
+      "unicode_decimal": 59036
+    },
+    {
+      "icon_id": "12322908",
+      "name": "sys01",
+      "font_class": "sys",
+      "unicode": "e69d",
+      "unicode_decimal": 59037
+    },
+    {
+      "icon_id": "12322914",
+      "name": "sys02",
+      "font_class": "sys1",
+      "unicode": "e69e",
+      "unicode_decimal": 59038
+    },
+    {
+      "icon_id": "12322915",
+      "name": "sys03",
+      "font_class": "sys2",
+      "unicode": "e69f",
+      "unicode_decimal": 59039
+    },
+    {
+      "icon_id": "12322918",
+      "name": "arrow",
+      "font_class": "arrow",
+      "unicode": "e6a0",
+      "unicode_decimal": 59040
+    }
+  ]
+}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 50 - 0
src/assets/font/iconfont.svg


BIN
src/assets/font/iconfont.ttf


BIN
src/assets/font/iconfont.woff


BIN
src/assets/font/iconfont.woff2


BIN
src/assets/img/01jk.png


BIN
src/assets/img/01jks.png


BIN
src/assets/img/02fb.png


BIN
src/assets/img/03mg.png


BIN
src/assets/img/04fb.png


BIN
src/assets/img/1.png


BIN
src/assets/img/2.png


BIN
src/assets/img/4dage-logo.png


BIN
src/assets/img/bar.png


BIN
src/assets/img/bg.png


BIN
src/assets/img/bg1.png


BIN
src/assets/img/bg2.png


BIN
src/assets/img/icon.png


BIN
src/assets/img/icon2.png


BIN
src/assets/img/icon2s.png


BIN
src/assets/img/logout.png


BIN
src/assets/img/noPicture.png


BIN
src/assets/img/user.png


BIN
src/assets/img/zhoushan-logo.jpg


+ 171 - 0
src/assets/style/public.css

@@ -0,0 +1,171 @@
+.layout{
+  width: 100%;
+  height: 100%;
+}
+
+.layout-con{
+  width: 100%;
+  height: 100%;
+  position: fixed;
+}
+
+
+.imgdiv{
+  position: relative;
+  
+}
+
+.imgdiv >i{
+  font-size: 20px;
+  position: absolute;
+  top: 5px;
+  right: 5px;
+}
+
+.middle-title, .register-title,.forget-title{
+  color: #4d4d4d;
+  font-size: 1.75rem;
+  text-align: center;
+  margin-bottom: 3.4375rem;
+  line-height: 1.5;
+}
+
+.register-title,.forget-title{
+  margin-top: 1.25rem;
+}
+
+.middle{
+  position: absolute;
+  top: 30vh;
+  left: 50vw;
+  width: 23.75rem;
+  height: 18.75rem;
+  transform: translate(-50%,-50%);
+}
+.middle-subtitle{
+  font-size: .875rem;
+  font-weight: 500;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+
+.form-bottom{
+  display: flex;
+  justify-content: space-between;
+  padding: 0 .625rem;
+  color: #888;
+}
+
+.form-bottom span{
+  cursor: pointer;
+}
+
+.bottom-div{
+  text-align: center;
+  cursor: pointer;
+  color: #888888;
+}
+
+.test-btn{
+  color: #67c23a!important;
+}
+
+.view-btn{
+  color: #409eff!important;
+}
+.re-apply-btn{
+  color: #f56c6c!important;
+}
+.apply-btn{
+  color: #ec652d!important;
+}
+
+.o-span{
+  cursor: pointer;
+  color: rgb(7, 152, 244);
+}
+
+
+.e-pagination{
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 1.5625rem;
+}
+
+:root{
+  --bg_color:rgba(255, 255, 255, 1);
+  --font_color:rgba(0, 0, 0, 0.88);
+  --font_color1:rgba(0, 0, 0, 0.38);
+}
+
+.theme{
+  background:url('~@/assets/img/bg1.png') no-repeat center center!important;
+  background-size: cover;
+}
+
+.theme-color{
+  color: var(--font_color)!important;
+}
+
+.theme-color1{
+  color: var(--font_color1)!important;
+}
+
+.card,.top-body {
+  background: var(--bg_color)!important;
+  border-radius: 2px!important;
+  color: #000!important;
+  border: none!important;
+}
+
+.el-table tr,.el-table th,.el-table{
+  background: none!important;
+  color: var(--font_color)!important;
+}
+
+.el-table th.is-leaf, .el-table td{
+  border-bottom: 1px solid rgba(0, 0, 0, 0.1)!important;
+  color:var(--font_color)!important;
+}
+
+table th > .cell{
+  color:var(--font_color1)!important;
+}
+
+.el-table--enable-row-hover .el-table__body tr:hover > td{
+  background: var(--bg_color)!important;
+}
+
+.el-table--group::after, .el-table--border::after, .el-table::before{
+  background: var(--bg_color)!important;
+}
+
+.el-pagination button:disabled{
+  background: none!important;
+}
+
+.el-pagination span:not([class*=suffix]), .el-pagination button{
+  color:var(--font_color)!important;
+}
+
+@media screen and (max-width: 1700px) {
+  html,body{
+    font-size: 15px;
+  }
+}
+
+
+@media screen and (max-width: 1400px) {
+  html,body{
+    font-size: 13px;
+  }
+}
+
+
+@media screen and (max-width: 1100px) {
+  html,body{
+    font-size: 12px;
+  }
+}

+ 109 - 0
src/assets/style/reset.css

@@ -0,0 +1,109 @@
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed, 
+figure, figcaption, footer, header, hgroup, 
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+  font-family: "Microsoft YaHei","Microsoft JhengHei";;
+	margin: 0;
+	padding: 0;
+	border: 0;
+	font-size: 100%;
+	vertical-align: baseline;
+}
+*{
+  box-sizing: border-box;
+}
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure, 
+footer, header, hgroup, menu, nav, section, main {
+	display: block;
+}
+html{
+	height: 100%;
+}
+body {
+	line-height: 1;
+	height: 100%;
+}
+html,body{
+	font-size: 16px;
+}
+ol, ul {
+	list-style: none;
+}
+blockquote, q {
+	quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+	content: '';
+	content: none;
+}
+table {
+	border-collapse: collapse;
+	border-spacing: 0;
+}
+button{outline:none; border: none;}
+input, button, select, textarea {
+outline: none;
+appearance: none;
+-webkit-appearance: none;
+border-radius: 0;
+-webkit-appearance: textfield;
+    background-color: white;
+    -webkit-rtl-ordering: logical;
+    cursor: text;
+    padding: 1px;
+    border-color: initial;
+    border-image: initial;
+}
+input::-webkit-outer-spin-button,input::-webkit-inner-spin-button{
+        -webkit-appearance:textfield;
+}
+input[type="number"]{
+        -moz-appearance:textfield;
+}
+input:focus { outline: none; } 
+select::-ms-expand {
+display: none;
+}
+
+
+::-webkit-scrollbar-track-piece {  
+	background-color:#ffffff;  
+}  
+::-webkit-scrollbar {  
+	width:8px;  
+	height:13px;  
+}  
+::-webkit-scrollbar-thumb {  
+	background-color:#e5e5e5;  
+	background-clip:padding-box;  
+	min-height:20px;  
+	border-radius: 3px;
+}  
+::-webkit-scrollbar-thumb:hover {  
+	background-color:#929292;  
+}  
+
+table th,
+table td {
+  text-align: center !important;
+}
+
+table th > .cell{
+	color: #000;
+}
+
+textarea{
+  height: 8rem!important;
+}

+ 281 - 0
src/components/cropper/index.vue

@@ -0,0 +1,281 @@
+<template>
+  <div class="custom-upload">
+    <el-dialog
+      title="图片裁剪"
+      :visible.sync="showCropper"
+      top="6vh"
+      width="50%"
+      height="700"
+      class="cropper-dialog"
+      center
+      append-to-body
+    >
+      <vue-cropper
+        v-if="showCropper"
+        id="corpper"
+        ref="cropper"
+        :class="{'corpper-warp':showCropper}"
+        v-bind="cropper"
+        :style="{height:`${height}px`}"
+      />
+      <div v-if="showCropper" class="cropper-button">
+        <el-button class="cancel-btn" size="small" @click.native="showCropper=false">取消</el-button>
+        <el-button size="small" type="primary" :loading="loading" @click="uploadCover">完成</el-button>
+      </div>
+    </el-dialog>
+    <input
+      :id="id"
+      type="file"
+      style="display: none"
+      name="single"
+      accept="image/*"
+      @change="onChange($event)"
+    />
+
+    <div class="avatar-uploader" @click="handleOpenFile()">
+      <div class="el-upload el-upload--text">
+        <div v-if="img" class="imgdiv">
+          <img
+            style="width: 100%;height:100%;"
+            :src="$serverName.replace('/zhoushan','') + img"
+          >
+          <i class="el-icon-circle-close" @click.stop="clearImg"></i>
+        </div>
+        <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+      </div>
+    </div>
+
+    <div v-if="tips" class="tips clear-margin-top">{{ tips }}</div>
+  </div>
+</template>
+
+<script>
+// 上传文件组件
+import { VueCropper } from 'vue-cropper'
+
+// 定义的接口根据自己项目更换
+
+import { isImageFile, isMaxFileSize, readFile } from '@/utils/upload' // 见下文
+import { Message } from 'element-ui'
+
+export default {
+  components: {
+    VueCropper
+  },
+  props: {
+    // 最大上传文件的大小
+    maxFileSize: {
+      type: Number,
+      default: 1024 // (MB)
+    },
+    uploadUrl: {
+      type: String
+    },
+    img: {
+      type: String
+    },
+    // 提示内容
+    tips: {
+      type: String
+    },
+    // 图片裁剪比列
+    fixedNumber: {
+      type: Array,
+      default: function () {
+        return []
+      }
+    },
+    // 图片文件分辨率的宽度
+    width: {
+      type: Number,
+      default: 8640
+    },
+    // 图片文件分辨率的高度
+    height: {
+      type: Number,
+      default: 1920
+    }
+  },
+  data () {
+    return {
+      id: 'cropper-input-' + new Date(),
+      loading: false,
+      showCropper: false,
+      imgName: '',
+      cropper: {
+        img: '',
+        info: true,
+        size: 1024 * 4,
+        outputType: 'jpg',
+        canScale: true,
+        autoCrop: true,
+        full: true,
+        // 只有自动截图开启 宽度高度才生效
+        autoCropWidth: this.width,
+        autoCropHeight: this.height,
+        fixedBox: false,
+        // 开启宽度和高度比例
+        fixed: true,
+        fixedNumber: this.fixedNumber,
+        original: false,
+        canMoveBox: true,
+        canMove: true
+      }
+    }
+  },
+  methods: {
+    // 打开文件
+    clearImg () {
+      this.$emit('clearImg')
+    },
+    handleOpenFile () {
+      const input = document.getElementById(this.id)
+      // 解决同一个文件不能监听的问题
+      input.addEventListener(
+        'click',
+        function () {
+          this.value = ''
+        },
+        false
+      )
+      // 点击input
+      input.click()
+    },
+
+    // 裁剪input 监听
+    async onChange (e) {
+      const file = e.target.files[0]
+
+      if (!file) {
+        return Message.error('选择图片失败')
+      }
+      // 验证文件类型
+      if (!isImageFile(file)) {
+        return
+      }
+      try {
+        // 读取文件
+        const src = await readFile(file)
+        this.imgName = file.name
+        this.showCropper = true
+        this.cropper.img = src
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // 封面上传功能
+    uploadCover () {
+      this.$refs.cropper.getCropBlob(async imgRes => {
+        try {
+          // 文件大小限制
+          if (!isMaxFileSize(imgRes, this.maxFileSize)) {
+            return
+          }
+          this.loading = true
+          let formData = new FormData()
+          formData.append('file', imgRes)
+          formData.append('filename', this.imgName)
+
+          const res = await this.$http.post(
+            this.uploadUrl,
+            formData,
+            {'Content-Type': 'multipart/form-data'})
+
+          this.$emit('subUploadSucceed', res.data)
+          Message.success('上传成功')
+          this.loading = false
+          this.showCropper = false
+        } catch (error) {
+          this.loading = false
+          this.showCropper = false
+          Message.error(error.data.message)
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="less"  >
+#corpper {
+  width: 90%;
+  margin: 0 auto;
+  background-image: none;
+  background: #fff;
+  z-index: 1002;
+  height: 512px;
+}
+.cropper-dialog {
+  height: 800px;
+  text-align: center;
+  .el-dialog__header {
+    padding-top: 15px;
+  }
+  .el-dialog--center .el-dialog__body {
+    padding-top: 0;
+    padding-bottom: 15px;
+  }
+  .el-dialog {
+    text-align: center;
+  }
+}
+.cropper-button {
+  z-index: 1003;
+  text-align: center;
+  margin-top: 20px;
+  .el-button {
+    font-size: 16px;
+    cursor: pointer;
+    text-align: center;
+  }
+  .cancel-btn {
+    color: #373737;
+  }
+  .el-button:last-child {
+    margin-left: 100px;
+  }
+}
+.cropper-modal {
+  background-color: rgba(0, 0, 0, 0.5) !important;
+}
+.custom-upload {
+  .tips {
+    margin-top: 10px;
+    color: red;
+    font-size: 12px;
+  }
+  .clear-margin-top {
+    margin-top: 0;
+  }
+}
+</style>
+
+<style>
+.avatar-uploader{
+  width: 180px;
+  max-height: 180px;
+}
+.avatar-uploader .el-upload {
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  /* height: 178px; */
+  display: block;
+}
+</style>

+ 58 - 0
src/components/crumbs/index.vue

@@ -0,0 +1,58 @@
+<!--  -->
+<template>
+<div class='crumbs card'><span v-for="(item,i) in data" :key='i'>{{item.name + (i === data.length - 1?'':' > ')}}</span></div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+export default {
+// import引入的组件需要注入到对象中才能使用
+  props: {
+    data: {
+      default: () => [],
+      type: Array
+    }
+  },
+  components: {},
+  data () {
+    // 这里存放数据
+    return {
+
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+<style scoped>
+.crumbs{
+  color: #000;
+  padding: 20px;
+  font-size: 1.125rem;
+  font-weight: bold;
+}
+
+</style>

+ 97 - 0
src/components/focus-bang/index.vue

@@ -0,0 +1,97 @@
+<template>
+  <div class="f-layout">
+    <div class="f-txt theme-color1">文物关注度排行</div>
+    <ul class="timeLine">
+      <li class="theme-color1" :class="{active:item.id===active}" @click="active = item.id" v-for="(item,i) in time" :key="i"><span>{{item.name}}</span></li>
+    </ul>
+    <div class="card-layout">
+      <WwCard class="ww" :data="item" v-for="(item,i) in data" :key="i"/>
+    </div>
+  </div>
+</template>
+<script>
+import WwCard from '@/components/ww-card'
+
+const time = [
+  {
+    name: '日',
+    id: 'day'
+  }, {
+    name: '周',
+    id: 'week'
+  }, {
+    name: '月',
+    id: 'mouth'
+  }, {
+    name: '季',
+    id: 'season'
+  }, {
+    name: '年',
+    id: 'year'
+  }
+]
+export default {
+  props: ['data'],
+  data () {
+    return {
+      time,
+      active: 'day'
+    }
+  },
+  components: {
+    WwCard
+  }
+}
+</script>
+
+<style scoped>
+.f-layout{
+  width: 100%;
+  height: 50%;
+  position: relative;
+}
+.f-txt{
+  position: absolute;
+  top: 1.5rem;
+  left: 1.5rem;
+  font-weight: bold;
+}
+.timeLine{
+  display: inline-block;
+  position: absolute;
+  top: 1.2rem;
+  left: 10.5rem;
+}
+.timeLine li{
+  display: inline-block;
+  width:36px;
+  height:24px;
+  border-radius:3px;
+  background:rgba(255,255,255,0.05);
+  position: relative;
+  cursor: pointer;
+  margin: 0 5px;
+}
+
+.timeLine li span{
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%,-50%);
+}
+
+.timeLine .active{
+  background:#532f1c;
+  color: #fff!important;
+}
+
+.card-layout{
+  margin: 60px 1.5rem;
+  display: flex;
+  justify-content: space-between;
+}
+
+.ww{
+  width: 32%!important;
+}
+</style>

+ 94 - 0
src/components/hot-bang/index.vue

@@ -0,0 +1,94 @@
+<template>
+  <div class="hot-layout">
+    <div class="h-txt theme-color1">文物热度榜</div>
+    <div class="hot-table">
+      <div class="hot-header">
+        <div class="theme-color1">
+          <span>序号</span>
+          <span>文物名称</span>
+        </div>
+        <span class="theme-color1">累计点赞数</span>
+      </div>
+      <ul>
+        <li v-for="(item,i) in data" :key="i">
+          <div>
+            <span class="xuhao" :class="{emxuhao:i===4}">{{i+1}}</span>
+            <span>{{item.name}}</span>
+          </div>
+          <span class="theme-color1">{{item.num}}</span>
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  props: ['data']
+}
+</script>
+
+<style scoped>
+.hot-layout{
+  position: relative;
+  height: 100%;
+}
+.h-txt{
+   position: absolute;
+  top: 1.5rem;
+  left: 1.5rem;
+  font-weight: bold;
+}
+.hot-table{
+  padding: 60px 1.5rem 0;
+}
+.hot-table .hot-header{
+  display: flex;
+  justify-content: space-between;
+}
+
+.hot-table .hot-header>div span:first-of-type{
+  width: 35px;
+  display: inline-block;
+}
+
+ul{
+  margin-top: 20px;
+  height: 290px;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+ul li{
+  display: flex;
+  justify-content: space-between;
+  text-align: center;
+  line-height: 1;
+  margin: 12px 0;
+}
+ul li>div span:first-of-type{
+  display: inline-block;
+  width: 35px;
+  position: relative;
+  z-index: 99;
+  color: #fff;
+  font-size: 14px;
+}
+ul li>div .xuhao::after{
+  content: '';
+  width: 16px;
+  height: 16px;
+  display: inline-block;
+  background: #f76b6c;
+  position: absolute;
+  border-radius: 2px;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%,-50%);
+  z-index: -1;
+}
+
+ul li>div .emxuhao::after{
+  background: #67c241;
+}
+
+</style>

+ 50 - 0
src/components/info-card/index.vue

@@ -0,0 +1,50 @@
+<template>
+  <div class="info card">
+    <i class="iconfont iconsys theme-color1" :class="data.icon"></i>
+    <p class="theme-color1">{{data.name}}</p>
+    <p class="theme-color1">
+      <strong v-for="(item,i) in data.sub1" :key="i">
+        <span class="theme-color">{{item.bold.txt}}</span>{{item.txt}}
+      </strong>
+    </p>
+    <p class="theme-color1">
+      <strong v-for="(sub,idx) in data.sub2" :key="idx">
+        <span class="theme-color">{{sub.bold.txt}}</span>{{sub.txt}}
+      </strong>
+    </p>
+  </div>
+</template>
+<script>
+export default {
+  props: ['data']
+}
+</script>
+<style scoped>
+  .theme-color{
+    color: #6c1c1c!important;
+  }
+  .info{
+    height: 100%;
+    padding: 1.5rem;
+    box-sizing: border-box;
+    position: relative;
+  }
+  .iconfont{
+    position: absolute;
+    right: 1.5rem;
+    top: 1.5rem;
+    font-size: 60px;
+  }
+  p:first-of-type{
+    margin-bottom: 30px;
+    font-weight: bold;
+  }
+  p{
+    margin-bottom: 10px;
+  }
+  span{
+    font-size: 36px;
+    display: inline-block;
+    margin-right: 10px;
+  }
+</style>

+ 59 - 0
src/components/main-top/index.vue

@@ -0,0 +1,59 @@
+<!--  -->
+<template>
+<div class='main-top'>
+  <crumbs :data="crumb" />
+  <slot name='con'></slot>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import Crumbs from '../crumbs'
+
+export default {
+// import引入的组件需要注入到对象中才能使用
+  props: {
+    crumb: {
+      default: () => [],
+      type: Array
+    }
+  },
+  components: {Crumbs},
+  data () {
+    // 这里存放数据
+    return {
+
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+<style scoped>
+.main-top{
+  background:none;
+}
+
+</style>

+ 57 - 0
src/components/nums/index.vue

@@ -0,0 +1,57 @@
+<template>
+  <div class="nums">
+    <div class="n-top "><span>{{data.sum}}</span></div>
+    <div class="n-bottom">{{data.name}}</div>
+  </div>
+</template>
+<script>
+export default {
+  props: ['data']
+}
+</script>
+<style scoped>
+  .nums{
+    height: 90%;
+    text-align: center;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    margin-top: 1%;
+  }
+  .n-top{
+    width: 100px;
+    height: 100px;
+    border-radius: 50%;
+    background-color: #DDCC92;
+    color: #6D1C1C;
+    /* background-color: rgba(255, 255, 255, 0.05); */
+    position: relative;
+  }
+
+  .n-top::before{
+    content: '';
+    border-radius: 50%;
+    background: none;
+    border: 2px solid rgba(167, 161, 95, 0.15);
+    width: 120px;
+    height: 120px;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%,-50%);
+  }
+
+  span{
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%,-50%);
+    font-size: 22px;
+    font-weight: bold;
+  }
+
+  .n-bottom{
+    margin-top: 20px;
+  }
+
+</style>

+ 28 - 0
src/components/pie-tu/index.vue

@@ -0,0 +1,28 @@
+<template>
+  <div class="trend">
+    <div class="pie-content" :id="id"></div>
+  </div>
+</template>
+<script>
+export default {
+  props: ['id', 'data'],
+  mounted () {
+    this.$nextTick(() => {
+      this.$chart.pie(
+        this.id,
+        this.data
+      )
+    })
+  }
+}
+</script>
+
+<style scoped>
+.trend{
+  position: relative;
+}
+.pie-content{
+  width: 100%;
+  height: 220px;
+}
+</style>

+ 46 - 0
src/components/power-bar/index.vue

@@ -0,0 +1,46 @@
+<template>
+  <div class="power-layout">
+    <div class="p-num" :style="{color:data.color}">{{data.num}}</div>
+    <ul>
+      <li v-for="(item,i) in sum" :style="{top:10*i+'px',background:i>(sum-data.content)?data.color:'rgba(255, 255, 255, 0.05)'}" :key='i'></li>
+    </ul>
+    <div class="b-num" >{{data.bottomname}}</div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: ['data'],
+  data () {
+    return {
+      sum: 25
+    }
+  }
+}
+</script>
+
+<style scoped>
+  .p-num{
+    text-align: center;
+    margin-bottom: 10px;
+  }
+  .b-num{
+    text-align: center;
+    margin-top: 265px;
+  }
+  ul{
+    font-size: 0;
+    position: relative;
+  }
+  ul li{
+    width: 100%;
+    display: inline-block;
+    vertical-align: middle;
+    height: 4px;
+    line-height: 4px;
+    background: rgba(255, 255, 255, 0.01);
+    position: absolute;
+    top: 10px;
+    border-radius: 2px;
+  }
+</style>

+ 108 - 0
src/components/search-bar/index.vue

@@ -0,0 +1,108 @@
+<!--  -->
+<template>
+<div class='search-bar'>
+  <div class="search-left">
+    <span>搜索条件:</span>
+    <div>
+      <el-input v-model="key"></el-input>
+    </div>
+    <div style="padding-left:.625rem">
+      <el-button @click="search" type="primary">搜索</el-button>
+    </div>
+  </div>
+  <div class="search-right">
+    <span>每页显示:</span>
+    <div class="search-select">
+      <el-select v-model="value" placeholder="请选择">
+        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
+        </el-option>
+      </el-select>
+    </div>
+  </div>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {},
+  data () {
+    // 这里存放数据
+    return {
+      key: '',
+      options: [{
+        value: 10,
+        label: '10'
+      }, {
+        value: 20,
+        label: '20'
+      }, {
+        value: 30,
+        label: '30'
+      }, {
+        value: 40,
+        label: '40'
+      }, {
+        value: 50,
+        label: '50'
+      }],
+      value: 10
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {
+    value (val) {
+      this.$emit('sizeChange', val)
+    }
+  },
+  // 方法集合
+  methods: {
+    search () {
+      this.$emit('seachKey', this.key)
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+
+<style scoped>
+.search-bar {
+  background-color: #fff;
+  display: flex;
+  justify-content: space-between;
+  width: 100%;
+}
+
+.search-bar span {
+  color: #888;
+  width: auto;
+}
+
+.search-left,.search-right {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.search-right .search-select{
+  width: 4.8rem;
+}
+</style>

+ 35 - 0
src/components/trend/index.vue

@@ -0,0 +1,35 @@
+<template>
+  <div class="trend card">
+    <div class="t-txt theme-color1">文物访问趋势-24h</div>
+    <div id="wwqs"></div>
+  </div>
+</template>
+<script>
+export default {
+  mounted () {
+    this.$nextTick(() => {
+      this.$chart.line2(
+        'wwqs',
+        ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+        [820, 932, 901, 934, 1290, 1330, 1320]
+      )
+    })
+  }
+}
+</script>
+
+<style scoped>
+.trend{
+  position: relative;
+}
+.trend .t-txt{
+  position: absolute;
+  top: 1.5rem;
+  left: 1.5rem;
+  font-weight: bold;
+}
+#wwqs{
+  width: 100%;
+  height: 400px;
+}
+</style>

+ 58 - 0
src/components/ww-card/index.vue

@@ -0,0 +1,58 @@
+<template>
+  <div class="ww-layout">
+    <p class="ph">NO.{{data.num}}</p>
+    <p>点赞数:{{data.zan}}</p>
+    <div class="ww-detail">
+      <p class="theme-color1">{{data.sub1}}</p>
+      <p class="theme-color1">{{data.sub2}}</p>
+    </div>
+    <p class="theme-color1">{{data.name}}</p>
+    <div class="img" :style="{backgroundImage: `url(${data.img})`}"></div>
+  </div>
+</template>
+<script>
+export default {
+  props: ['data']
+}
+</script>
+<style scoped>
+.ww-layout{
+  width:100%;
+  height:200px;
+  background:rgba(255,255,255,0.05);
+  border-radius:3px;
+  position: relative;
+  overflow: hidden;
+  padding: 1rem;
+}
+
+.ww-layout .img{
+  position: absolute;
+  right: 0;
+  top: 0;
+  width: 200px;
+  height: 200px;
+  background-image: url(https://show.4dage.com/3D/2018/model/SD/images/s02.jpg);
+  background-position: center;
+  background-size: auto 100%;
+  background-repeat: no-repeat;
+}
+
+.ph{
+  color:#532f1c;
+  font-size: 32px;
+  font-weight: bold;
+}
+.ww-detail{
+  margin: 25px 0;
+}
+
+.ww-detail p{
+  margin-bottom: 4px;
+}
+
+p{
+  margin-bottom: 12px;
+}
+
+</style>

+ 72 - 0
src/configue/base.js

@@ -0,0 +1,72 @@
+const base = {
+  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}$/
+  },
+  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
+    }
+  },
+  isTypeBySend: function (fileName, typeArr) {
+    if (typeof fileName !== 'string') return
+    let name = fileName.toLowerCase()
+    let boo = false
+    typeArr.forEach(item => {
+      console.log(name.endsWith(item))
+      if (name.endsWith(item)) {
+        boo = true
+      }
+    })
+    return boo
+  },
+  timestampToTime: function (timestamp) {
+    var date = new Date(Number(timestamp))// 时间戳为10位需*1000,时间戳为13位的话不需乘1000
+
+    var Y = date.getFullYear() + '-'
+
+    var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'
+
+    var D = date.getDate() + ' '
+
+    // var h = date.getHours() + ':'
+
+    // var m = date.getMinutes() + ':'
+
+    // var s = date.getSeconds()
+
+    return Y + M + D
+  },
+  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
+  }
+}
+export { base }

+ 3 - 0
src/configue/bus.js

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

+ 84 - 0
src/configue/http.js

@@ -0,0 +1,84 @@
+import axios from 'axios'
+import Vue from 'vue'
+import router from '../router'
+
+var isProduction = process.env.NODE_ENV === 'production'
+const vue = new Vue()
+let loading = ''
+
+// 配置请求域名
+
+const serverName = isProduction ? '/zhoushan' : 'http://119.23.129.199:8110/zhoushan'
+// http://119.23.129.199:8100/
+const exceptUrls = ['/login']
+
+axios.defaults.baseURL = serverName
+axios.defaults.headers['X-Requested-with'] = 'XMLHttpRequest'
+
+axios.interceptors.request.use(function (config) {
+  for (let i = 0; i < exceptUrls.length; i++) {
+    let url = exceptUrls[i]
+    if (config.url.indexOf(url) > -1) {
+      config.baseURL = serverName.replace('/zhoushan', '')
+    }
+  }
+  config.headers['token'] = window.localStorage.getItem('token')
+  loading = vue.$loading({
+    lock: true,
+    text: 'Loading',
+    spinner: 'el-icon-loading',
+    background: 'rgba(0, 0, 0, 0.7)'
+  })
+  return config
+}, function (error) {
+  // 对请求错误做些什么
+  return Promise.reject(error)
+})
+
+// 配置response拦截器
+axios.interceptors.response.use(
+
+  response => {
+    loading.close()
+    let data = response.data
+    let code = Number(response.data.code)
+
+    switch (code) {
+      case -1:
+        break
+      case 102:
+        break
+      case 5001:
+        window.localStorage.setItem('token', '')
+        vue.$alert('登录状态失效,请重新登录', '提示', {
+          confirmButtonText: '确定',
+          callback: function () {
+            router.push('/login')
+          }
+        })
+        break
+      case 0:
+        break
+    }
+    // tryHideFullScreenLoading()
+    return data
+  },
+  error => {
+    loading.close()
+    if (error.response) {
+      switch (error.response.code) {
+        case 5001:
+          window.localStorage.setItem('token', '')
+          vue.$alert('登录状态失效,请重新登录', '提示', {
+            confirmButtonText: '确定',
+            callback: function () {
+              router.push('/login')
+            }
+          })
+          break
+      }
+    }
+    return Promise.reject(error)
+  }
+)
+export { serverName, axios }

+ 251 - 0
src/configue/myCharts.js

@@ -0,0 +1,251 @@
+/**
+ * 各种画echarts图表的方法都封装在这里
+ * 注意:这里echarts没有采用按需引入的方式,只是为了方便学习
+ */
+
+import echarts from 'echarts'
+const install = function (Vue) {
+  Object.defineProperties(Vue.prototype, {
+    $chart: {
+      get () {
+        return {
+          // 统计分析
+          line1: function (id, header, data) {
+            this.chart = echarts.init(document.getElementById(id))
+            this.chart.clear()
+
+            const optionData = {
+              xAxis: {
+                type: 'category',
+                data: header
+              },
+              yAxis: {
+                type: 'value'
+              },
+              series: [{
+                data: data,
+                type: 'line',
+                smooth: true
+              }]
+            }
+
+            this.chart.setOption(optionData)
+          },
+          // 访问人数
+          pie: function (id, data) {
+            this.chart = echarts.init(document.getElementById(id))
+            this.chart.clear()
+            var fontColor = '#000'
+
+            const optionData = {
+              tooltip: {
+                trigger: 'item',
+                formatter: '{b}: {c} ({d}%)'
+              },
+              legend: {
+                orient: 'vertical',
+                x: 'left',
+                y: '15',
+                textStyle: {
+                  color: fontColor
+                },
+                data: data.header
+              },
+              series: [
+                {
+                  type: 'pie',
+                  radius: ['55%', '70%'],
+                  center: data.center || ['50%', '60%'],
+                  color: data.color || ['#67c241', '#e6a139', '#f76b6c'],
+                  avoidLabelOverlap: false,
+                  label: {
+                    normal: {
+                      show: false,
+                      position: 'center'
+                    },
+                    emphasis: {
+                      show: true,
+                      textStyle: {
+                        fontSize: '20',
+                        fontWeight: 'bold',
+                        color: '#000'
+                      }
+                    }
+                  },
+                  labelLine: {
+                    normal: {
+                      show: false
+                    }
+                  },
+                  data: data.data
+                }
+              ]
+            }
+
+            this.chart.setOption(optionData)
+          },
+          // 文物趋势
+          line2: function (id, header, data) {
+            this.chart = echarts.init(document.getElementById(id))
+            this.chart.clear()
+            var fontColor = '#000'
+            var borderColor = 'rgba(0,0,0,0.1)'
+            const optionData = {
+              grid: {
+                left: '5%',
+                right: '8%',
+                top: '18%',
+                bottom: '5%',
+                containLabel: true
+              },
+              tooltip: {
+                show: true,
+                trigger: 'item'
+              },
+              legend: {
+                show: true,
+                x: '200',
+                y: '22',
+                icon: 'stack',
+                itemWidth: 10,
+                itemHeight: 10,
+                textStyle: {
+                  color: fontColor
+                },
+                data: ['全部', '青铜', '瓷器', '陶器']
+              },
+              xAxis: [{
+                type: 'category',
+                boundaryGap: false,
+                axisLabel: {
+                  color: fontColor
+                },
+                axisLine: {
+                  show: true,
+                  lineStyle: {
+                    color: borderColor
+                  }
+                },
+                axisTick: {
+                  show: false
+                },
+                splitLine: {
+                  show: true,
+                  lineStyle: {
+                    color: borderColor
+                  }
+                },
+                data: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
+              }],
+              yAxis: [{
+                type: 'value',
+                axisLabel: {
+                  formatter: '{value}',
+                  textStyle: {
+                    color: fontColor
+                  }
+                },
+                axisLine: {
+                  lineStyle: {
+                    color: borderColor
+                  }
+                },
+                axisTick: {
+                  show: false
+                },
+                splitLine: {
+                  show: true,
+                  lineStyle: {
+                    color: borderColor
+                  }
+                }
+              }],
+              series: [
+                {
+                  name: '青铜',
+                  type: 'line',
+                  stack: '总量',
+                  symbol: 'rect',
+                  symbolSize: 9,
+                  itemStyle: {
+                    normal: {
+                      color: '#67c241',
+                      lineStyle: {
+                        color: '#67c241',
+                        width: 1
+                      }
+                    }
+                  },
+                  data: [220, 182, 191, 234, 290, 330, 310, 201, 154, 190, 330, 410]
+                },
+                {
+                  name: '瓷器',
+                  type: 'line',
+                  stack: '总量',
+                  symbol: 'rect',
+                  symbolSize: 9,
+                  itemStyle: {
+                    normal: {
+                      color: '#e6a139',
+                      lineStyle: {
+                        color: '#e6a139',
+                        width: 1
+                      }
+                    }
+                  },
+                  data: [150, 22, 201, 154, 190, 330, 410, 150, 232, 201, 154, 190]
+                },
+                {
+                  name: '陶器',
+                  type: 'line',
+                  stack: '总量',
+                  symbol: 'rect',
+                  symbolSize: 9,
+                  itemStyle: {
+                    normal: {
+                      color: '#f76b6c',
+                      lineStyle: {
+                        color: '#f76b6c',
+                        width: 1
+                      }
+                    }
+                  },
+                  data: [0, 182, 191, 234, 0, 330, 10, 201, 154, 190, 330, 410]
+                },
+                {
+                  name: '全部',
+                  type: 'line',
+                  stack: '总量',
+                  symbol: 'rect',
+                  symbolSize: 9,
+                  itemStyle: {
+                    normal: {
+                      color: '#000',
+                      lineStyle: {
+                        color: '#000',
+                        width: 1
+                      }
+                    }
+                  },
+                  markPoint: {
+                    itemStyle: {
+                      normal: {
+                        color: 'red'
+                      }
+                    }
+                  },
+                  data: [120, 120, 301, 134, 390, 630, 810, 120, 491, 120, 290, 330]
+                }
+              ]
+            }
+            this.chart.setOption(optionData)
+          }
+        }
+      }
+    }
+  })
+}
+
+export default {
+  install
+}

+ 40 - 0
src/main.js

@@ -0,0 +1,40 @@
+// 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 Vue from 'vue'
+import App from './App'
+import ElementUI from 'element-ui'
+import router from './router'
+import {base} from '@/configue/base'
+import {axios, serverName} from './configue/http'
+import myCharts from '@/configue/myCharts.js'
+import Vue2Editor from 'vue2-editor'
+import '../theme/index.css'
+import less from 'less'
+
+Vue.use(less)
+
+Vue.use(Vue2Editor)
+Vue.use(myCharts)
+
+Vue.use(ElementUI)
+Vue.config.productionTip = false
+
+Vue.prototype.$base = base
+Vue.prototype.$bus = new Vue()
+Vue.prototype.$http = axios
+Vue.prototype.$serverName = serverName// 挂载到Vue实例上面
+Vue.prototype.isTypeBySend = base.isTypeBySend
+Vue.prototype.vLoading = {
+  lock: true,
+  text: 'Loading',
+  spinner: 'el-icon-loading',
+  background: 'rgba(0, 0, 0, 0.7)'
+}
+
+/* eslint-disable no-new */
+new Vue({
+  el: '#app',
+  router,
+  components: { App },
+  template: '<App/>'
+})

+ 239 - 0
src/pages/cultural-relic/index.vue

@@ -0,0 +1,239 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData"></main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span>按文物类别查看:</span>
+            <el-select style="width:100px;" v-model="typeId" placeholder="请选择">
+              <el-option label="全部" value=""></el-option>
+              <el-option v-for="(item,i) in plist" :key="i" :label="item.name" :value="item.id"></el-option>
+            </el-select>
+            <span style="margin-left:20px;">按文物年代查看:</span>
+            <el-select style="width:100px;" v-model="timeId" placeholder="请选择">
+              <el-option label="全部" value=""></el-option>
+              <el-option v-for="(item,i) in tlist" :key="i" :label="item.name" :value="item.id"></el-option>
+            </el-select>
+            <el-input style="width:220px;margin:0 20px;" v-model="inputKey" placeholder="请输入文物名称搜索"></el-input>
+            <el-button type="primary" @click="getInformation">查找</el-button>
+            <el-button @click="inputKey=''">重置</el-button>
+            <el-select style="margin-left:20px;" @change="piliang" :value="'批量导入 '" placeholder="请选择">
+              <el-option
+                label="模板下载"
+                value="模板下载">
+              </el-option>
+              <el-option
+                label="批量导入"
+                value="批量导入">
+              </el-option>
+            </el-select>
+            <input @change="uploadChange" class="upload-btn" ref="upload" type="file">
+          </div>
+          <div class="info-right">
+            <el-button type="primary" @click="$router.push({name:'edit-cultural-relic',params:{type:0}})">新增文物</el-button>
+          </div>
+        </div>
+        <div class="collection-con">
+          <ul>
+            <li class="theme-color" @click="gotoShow(item)" v-for="(item,i) in tableData" :key="i">
+              <div class="li-img">
+                <el-image :fit="'cover'" style="width:100%;height:100%;" :src="item.unityPic"></el-image>
+                <div class="liulan"><span>浏览量: {{Math.round(Math.random()*100000)}}</span> 点赞数: {{Math.round(Math.random()*1000)}}</div>
+              </div>
+              <div>{{item.timeName}} {{item.typeName}} <span @click.stop="del(item)" class="del">删除</span></div>
+              <p>{{item.name}}</p>
+            </li>
+          </ul>
+        </div>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="currentPage"
+            :page-size="size"
+            layout="prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+import SearchBar from '@/components/search-bar'
+const crumbData = [
+  {
+    name: '文物库',
+    id: 4
+  }
+]
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+    SearchBar
+  },
+  data () {
+    return {
+      crumbData,
+      tableData: [],
+      inputKey: '',
+      currentPage: 1,
+      size: 20,
+      total: 0,
+      loading: false,
+      plist: [],
+      tlist: [],
+      typeId: '',
+      timeId: ''
+    }
+  },
+  watch: {
+    currentPage () {
+      this.refresh()
+    },
+    size () {
+      this.refresh()
+    },
+    inputKey () {
+      this.refresh()
+    }
+  },
+  mounted () {
+    this.getPositionList()
+    this.getTypeList()
+    this.refresh()
+  },
+  methods: {
+    del (item) {
+      let data = {
+        id: item.id
+      }
+      this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http.post('/collection/deleteCollection', data).then(res => {
+          if (res.code === 0) {
+            this.$alert('删除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.msg
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    async uploadChange (e) {
+      let file = e.target.files[0]
+      let formData = new FormData()
+      formData.append('file', file)
+      const res = await this.$http.post(
+        '/collection/importCollection',
+        formData,
+        {'Content-Type': 'multipart/form-data'})
+      if (res.code === 0) {
+        this.$alert(`上传成功`, '提示', {
+          confirmButtonText: '确定',
+          callback: action => {
+            this.refresh()
+          }
+        })
+      } else {
+        this.$alert(`上传失败,${res.msg}`, '提示', {
+          confirmButtonText: '确定',
+          callback: action => {
+            this.refresh()
+          }
+        })
+      }
+    },
+    piliang (data) {
+      if (data === '模板下载') {
+        window.open('/collection/importData.xlsx', '_blank')
+      } else {
+        this.$refs.upload.click()
+      }
+    },
+    async getPositionList () {
+      let result = await this.$http({
+        method: 'post',
+        data: {
+          state: 0
+        },
+        url: '/collection/typeList'
+      })
+
+      this.plist = result.data
+    },
+    async getTypeList () {
+      let result = await this.$http({
+        method: 'post',
+        url: '/collection/timeList'
+      })
+
+      this.tlist = result.data
+    },
+    gotoShow (item) {
+      this.$router.push({ name: 'show-cultural-relic', params: { id: item.id } })
+    },
+    goto (item) {
+      window.localStorage.setItem('editCollection', JSON.stringify(item))
+      this.$router.push({ name: 'edit-collection', params: { type: 1 } })
+    },
+    refresh () {
+      this.loading = true
+      this.getInformation()
+      this.loading = false
+    },
+    handleCurrentChange (val) {
+      this.currentPage = val
+    },
+    async getInformation () {
+      let params = {
+        name: this.inputKey,
+        typeId: this.typeId,
+        timeId: this.timeId,
+        pageNum: this.currentPage,
+        pageSize: this.size
+      }
+
+      let result = await this.$http({
+        method: 'post',
+        data: params,
+        url: '/collection/list'
+      })
+
+      if (result.code !== 0) {
+        return
+      }
+      this.tableData = result.data.list
+      this.total = result.data.total
+    }
+  }
+}
+</script>
+
+<style scoped>
+/* 引入公共css类 */
+@import url(./style);
+</style>

+ 155 - 0
src/pages/cultural-relic/style.css

@@ -0,0 +1,155 @@
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.upload-btn{
+  opacity: 0;
+  width: 0;
+}
+
+.top-body .top-con{
+  font-weight: bold;
+}
+.table-title{
+  padding: 1rem 1rem 1rem 0 ;
+  font-size: 1rem;
+  color: #2d2d2d;
+  border-bottom: 1px solid #ccc;
+  display: flex;
+  justify-content: space-between;
+}
+
+.more{
+  color: #ec652d;
+  cursor: pointer;
+}
+
+.top-right{
+  background-color: #ec652d;
+  height: 3.5625rem;
+  line-height: 3.5625rem;
+  color: #fff;
+  padding: 0 1.875rem;
+  border-radius: .3125rem;
+  font-size: 1.125rem;
+  font-weight: bold;
+}
+
+.search-body{
+  background-color: #fff;
+  margin: 1.25rem 0;
+}
+
+.interface-table{
+  height: calc(100% - 17.1875rem);
+  overflow-x: hidden;
+  background-color: #fff;
+  padding: 0 1.125rem 2.375rem;
+  box-sizing: border-box;
+}
+
+.zan-con{
+  display: flex;
+  width: 100%;
+  justify-content: space-around;
+  margin-top: 1.5rem;
+  text-align: center;
+  font-size: 1.125rem;
+}
+
+.zan-con .line{
+  height: 8rem;
+  width: 1px;
+  background: #ccc;
+}
+
+.zan-con .zan-contain{
+  display: flex;
+  justify-content: space-between;
+  flex-direction: column;
+}
+
+.zan-con .zan-contain p{
+  font-size: 2.25rem;
+}
+
+.zan-con .zan-contain p:first-child{
+  font-size: .875rem;
+  line-height: 1.5;
+}
+
+.zan-sub{
+  text-align: right;
+  margin-top: 1.25rem;
+  color: #a5a5a5;
+  font-size: .875rem;
+}
+
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+}
+
+
+.info-top{
+  padding: 20px 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px #a5a5a5 solid;
+}
+
+.o-span{
+  cursor: pointer;
+  color: rgb(7, 152, 244);
+}
+
+.collection-con{
+  width: 100%;
+}
+
+.collection-con ul{
+  display: flex;
+  flex-wrap: wrap;
+  margin-top: 20px;
+}
+
+.collection-con ul li {
+  width: 19%;
+  margin-right: 1%;
+  cursor: pointer;
+  font-size: .8rem;
+  color: #2d2d2d;
+  margin-bottom: 20px;
+}
+
+.collection-con ul .li-img {
+  position: relative;
+  height: 200px;
+  margin-bottom: 10px;
+}
+.collection-con ul .li-img > .liulan{
+  position: absolute;
+  left: 10px;
+  bottom: 10px;
+  color: #fff;
+}
+
+.collection-con ul .del{
+  float: right;
+}
+
+.collection-con ul .li-img div span{
+  margin-right: 10px;
+}
+
+
+.collection-con ul img {
+  width: 100%;
+}

+ 294 - 0
src/pages/device/index.vue

@@ -0,0 +1,294 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData"></main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left"></div>
+          <div class="info-right">
+            <el-button type="primary"  @click="show('','add')">新增设备</el-button>
+          </div>
+        </div>
+        <el-table :data="tableData" style="width: 100%">
+          <el-table-column
+            v-for="(item, idx) in data"
+            :key="idx"
+            :prop="item.prop"
+            :label="item.label"
+          >
+            <template slot-scope="scope">
+              <span>{{scope.row[item.prop]}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span class="o-span" @click="show(scope.row,'edit')">编辑</span>
+              <span class="o-span" @click="changeState(scope.row)">{{scope.row.qiyong==='启用'?'停用':'启用'}}</span>
+            </template>
+          </el-table-column>
+          <div class="e-pagination">
+            <el-pagination @current-change="handleCurrentChange" :current-page.sync="currentPage" :page-size="size" layout="prev, pager, next, jumper" :total="total">
+            </el-pagination>
+          </div>
+        </el-table>
+      </div>
+    </div>
+    <el-dialog title="新增设备" :visible.sync="dialogFormVisible" width="40%">
+      <el-form :model="form">
+        <el-form-item label="设备名称:" style="width:50%;" :label-width="formLabelWidth">
+          <el-input v-model="form.name" placeholder="请输入设备名称" autocomplete="off"></el-input>
+        </el-form-item>
+        <el-form-item label="设备ID:" style="width:50%;" :label-width="formLabelWidth">
+          <el-input v-model="form.uuid" placeholder="请输入设备ID" autocomplete="off"></el-input>
+        </el-form-item>
+        <el-form-item label="所在位置:" :label-width="formLabelWidth">
+          <el-select v-model="form.positionId" placeholder="请选择活动区域">
+            <el-option v-for="(item,i) in plist" :key="i" :label="item.name" :value="item.id"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="是否启用:" :label-width="formLabelWidth">
+            <el-radio-group v-model="form.state">
+            <el-radio :label="0" >是</el-radio>
+            <el-radio :label="1" >否</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary"  @click="save">保 存</el-button>
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+const crumbData = [
+  {
+    name: '设备管理',
+    id: 10
+  }
+]
+
+let juese = {
+  0: '高级管理员',
+  1: '普通管理员'
+}
+
+let zt = {
+  0: '启用',
+  1: '停用'
+}
+
+let urlType = {
+  add: '/equipment/addEquipment',
+  edit: '/equipment/updateEquipment'
+}
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop
+  },
+  data () {
+    // 这里存放数据
+    let data = [
+      {
+        prop: 'id',
+        label: '序号'
+      },
+      {
+        prop: 'name',
+        label: '设备名称'
+      },
+      {
+        prop: 'uuid',
+        label: '设备ID'
+      },
+      {
+        prop: 'positionName',
+        label: '所在位置'
+      },
+      {
+        prop: 'qiyong',
+        label: '状态'
+      }
+    ]
+
+    return {
+      crumbData,
+      data,
+      region: 0,
+      infoName: '',
+      tableData: [],
+      dialogTableVisible: false,
+      dialogFormVisible: false,
+      form: {
+        id: '',
+        name: '',
+        uuid: '',
+        positionId: '',
+        state: '',
+        positionName: ''
+      },
+      plist: [],
+      inputKey: '',
+      currentPage: 1,
+      size: 10,
+      total: 0,
+      formLabelWidth: '120px',
+      imageUrl: '',
+      type: 'add'
+    }
+  },
+  watch: {
+    currentPage () {
+      this.refresh()
+    },
+    size () {
+      this.refresh()
+    },
+    region () {
+      this.refresh()
+    },
+    inputKey () {
+      this.refresh()
+    }
+  },
+  mounted () {
+    this.getPositionList()
+    this.refresh()
+  },
+  methods: {
+    goto (item) {
+      window.localStorage.setItem('editInfo', JSON.stringify(item))
+      this.$router.push({name: 'edit-information', params: {type: 1}})
+      this.$bus.$emit('editinfo', item)
+    },
+    upload_success (data) {
+      this.form.head = data.data
+    },
+    refresh () {
+      this.loading = true
+      this.getInformation()
+      this.loading = false
+    },
+    handleCurrentChange (val) {
+      this.currentPage = val
+    },
+    save () {
+      let {userName, roleId, phone, head, state} = this.form
+      let data = {userName, roleId, phone, head, state}
+
+      this.$http.post(urlType[this.type], data).then(res => {
+        if (res.code === 0) {
+          this.$alert('操作成功', '提示', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.dialogFormVisible = false
+              this.refresh()
+            }
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+
+    show (item = '', type) {
+      this.dialogFormVisible = true
+      this.type = type
+      this.form = {
+        id: '',
+        name: '',
+        uuid: '',
+        positionId: '',
+        state: '',
+        positionName: ''
+      }
+
+      if (type === 'edit') {
+        this.form = item
+      }
+    },
+    async getPositionList () {
+      let result = await this.$http({
+        method: 'post',
+        url: '/position/list'
+      })
+
+      this.plist = result.data
+    },
+    changeState (item) {
+      let state = item.state === 1 ? 0 : 1
+      let data = {
+        id: item.id,
+        state
+      }
+
+      this.$confirm('此操作将导致设备状态发生改变, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http.post('/equipment/updateState', data).then(res => {
+          if (res.code === 0) {
+            this.$alert('修改成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.msg
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消'
+        })
+      })
+    },
+
+    async getInformation () {
+      let params = {
+        pageNum: this.currentPage,
+        pageSize: this.size
+      }
+
+      let result = await this.$http({
+        method: 'post',
+        data: params,
+        url: '/equipment/list'
+      })
+
+      if (result.code !== 0) {
+        return
+      }
+      this.tableData = result.data.list
+      this.total = result.data.total
+      this.tableData.forEach(item => {
+        item['date'] = this.$base.timestampToTime(item['startTime']) + '至' + this.$base.timestampToTime(item['endTime'])
+        item['role'] = juese[item['roleId']]
+        item['qiyong'] = zt[item['state']]
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+/* 引入公共css类 */
+@import url(./style);
+</style>

+ 106 - 0
src/pages/device/style.css

@@ -0,0 +1,106 @@
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.top-body .top-con{
+  font-weight: bold;
+}
+.table-title{
+  padding: 1rem 1rem 1rem 0 ;
+  font-size: 1rem;
+  color: #2d2d2d;
+  border-bottom: 1px solid #ccc;
+  display: flex;
+  justify-content: space-between;
+}
+
+.more{
+  color: #ec652d;
+  cursor: pointer;
+}
+
+.top-right{
+  background-color: #ec652d;
+  height: 3.5625rem;
+  line-height: 3.5625rem;
+  color: #fff;
+  padding: 0 1.875rem;
+  border-radius: .3125rem;
+  font-size: 1.125rem;
+  font-weight: bold;
+}
+
+.search-body{
+  background-color: #fff;
+  margin: 1.25rem 0;
+}
+
+.interface-table{
+  height: calc(100% - 17.1875rem);
+  overflow-x: hidden;
+  background-color: #fff;
+  padding: 0 1.125rem 2.375rem;
+  box-sizing: border-box;
+}
+
+.zan-con{
+  display: flex;
+  width: 100%;
+  justify-content: space-around;
+  margin-top: 1.5rem;
+  text-align: center;
+  font-size: 1.125rem;
+}
+
+.zan-con .line{
+  height: 8rem;
+  width: 1px;
+  background: #ccc;
+}
+
+.zan-con .zan-contain{
+  display: flex;
+  justify-content: space-between;
+  flex-direction: column;
+}
+
+.zan-con .zan-contain p{
+  font-size: 2.25rem;
+}
+
+.zan-con .zan-contain p:first-child{
+  font-size: .875rem;
+  line-height: 1.5;
+}
+
+.zan-sub{
+  text-align: right;
+  margin-top: 1.25rem;
+  color: #a5a5a5;
+  font-size: .875rem;
+}
+
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+}
+
+
+.info-top{
+  padding: 20px 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px #a5a5a5 solid;
+}
+
+.o-span{
+  cursor: pointer;
+  color: rgb(7, 152, 244);
+}

+ 236 - 0
src/pages/display/index.vue

@@ -0,0 +1,236 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData"></main-top>
+    <div class="table-interface">
+      <div class="top-body" v-loading="loading"
+    element-loading-text=""
+    element-loading-spinner="el-icon-loading"
+    element-loading-background="rgba(0, 0, 0, 0.6)">
+        <div class="info-top">
+          <div class="info-left">
+            <span >展示方案:</span>
+            <el-input style="width:220px;margin-right:20px;" v-model="inputKey" placeholder="请输入展示方案名称"></el-input>
+            <el-button type="primary" @click="getInformation">查找</el-button>
+            <el-button @click="inputKey=''">重置</el-button>
+          </div>
+          <div class="info-right">
+            <el-button type="primary" @click="$router.push({name:'edit-display',params:{type:0,id:'none'}})">新增方案</el-button>
+          </div>
+        </div>
+        <el-table  :data="tableData" style="width: 100%">
+          <el-table-column
+            v-for="(item, idx) in data"
+            :key="idx"
+            :prop="item.prop"
+            :label="item.label"
+          >
+          <template slot-scope="scope">
+            <span>{{scope.row[item.prop]}}</span>
+          </template>
+          </el-table-column>
+          <el-table-column label="状态">
+            <template slot-scope="scope" v-if="scope.row.qiyong">
+              <el-switch
+                @change='changeState(scope.row)'
+                v-model="scope.row.qiyong.st"
+              >
+              </el-switch>
+              <span >{{scope.row.qiyong.text}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span class="o-span" @click="goto(scope.row)">编辑</span>
+              <span class="o-span" @click="del(scope.row)">删除</span>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination @current-change="handleCurrentChange" :current-page.sync="currentPage" :page-size="size" layout="prev, pager, next, jumper" :total="total">
+          </el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+const crumbData = [
+  {
+    name: '展示管理',
+    id: 3
+  }
+]
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop
+  },
+  data () {
+    // 这里存放数据
+    let data = [
+      {
+        prop: 'idx',
+        label: '序号'
+      },
+      {
+        prop: 'name',
+        label: '展示方案'
+      },
+      {
+        prop: 'typeName',
+        label: '展示类别'
+      },
+      {
+        prop: 'date',
+        label: '发布时间'
+      }
+    ]
+
+    return {
+      crumbData,
+      data,
+      loading: true,
+      tableData: [],
+      inputKey: '',
+      currentPage: 1,
+      size: 10,
+      total: 0
+    }
+  },
+  watch: {
+    currentPage () {
+      this.refresh()
+    },
+    size () {
+      this.refresh()
+    },
+    inputKey () {
+      this.refresh()
+    }
+  },
+  mounted () {
+    this.refresh()
+  },
+  methods: {
+    goto (item) {
+      this.$router.push({ name: 'edit-display', params: { type: 1, id: item.id } })
+    },
+    async changeState (item) {
+      this.loading = true
+
+      let { name, id, typeId, equipmentId, description } = item
+      let data = { name, typeId, equipmentId, isSend: 1, state: !item.qiyong.st ? 1 : 0, description, id }
+      this.$http.post('/exhibition/updateExhibition', data).then(res => {
+        if (res.code === 0) {
+          this.loading = false
+          this.refresh()
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    refresh () {
+      this.loading = true
+      this.getInformation()
+      this.loading = false
+    },
+    handleCurrentChange (val) {
+      this.currentPage = val
+    },
+    del (item) {
+      let data = {
+        id: item.id
+      }
+      this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http.post('/exhibition/deleteExhibition', data).then(res => {
+          if (res.code === 0) {
+            this.$alert('删除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.msg
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    fixState (state) {
+      let obj = {}
+      switch (Number(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
+    },
+    async getInformation () {
+      let params = {
+        name: this.inputKey,
+        pageNum: this.currentPage,
+        pageSize: this.size
+      }
+      let result = await this.$http({
+        method: 'post',
+        data: params,
+        url: '/exhibition/list'
+      })
+
+      if (result.code !== 0) {
+        return
+      }
+      this.tableData = result.data.list
+      this.total = result.data.total
+      this.tableData.forEach((item, i) => {
+        item['date'] = this.$base.timestampToTime(item['createTime'])
+        item['qiyong'] = this.fixState(item['state'])
+        item['idx'] = i + 1
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+/* 引入公共css类 */
+@import url(./style);
+</style>

+ 112 - 0
src/pages/display/style.css

@@ -0,0 +1,112 @@
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.top-body .top-con{
+  font-weight: bold;
+}
+.table-title{
+  padding: 1rem 1rem 1rem 0 ;
+  font-size: 1rem;
+  color: #2d2d2d;
+  border-bottom: 1px solid #ccc;
+  display: flex;
+  justify-content: space-between;
+}
+
+.more{
+  color: #ec652d;
+  cursor: pointer;
+}
+
+.top-right{
+  background-color: #ec652d;
+  height: 3.5625rem;
+  line-height: 3.5625rem;
+  color: #fff;
+  padding: 0 1.875rem;
+  border-radius: .3125rem;
+  font-size: 1.125rem;
+  font-weight: bold;
+}
+
+.search-body{
+  background-color: #fff;
+  margin: 1.25rem 0;
+}
+
+.interface-table{
+  height: calc(100% - 17.1875rem);
+  overflow-x: hidden;
+  background-color: #fff;
+  padding: 0 1.125rem 2.375rem;
+  box-sizing: border-box;
+}
+
+.zan-con{
+  display: flex;
+  width: 100%;
+  justify-content: space-around;
+  margin-top: 1.5rem;
+  text-align: center;
+  font-size: 1.125rem;
+}
+
+.zan-con .line{
+  height: 8rem;
+  width: 1px;
+  background: #ccc;
+}
+
+.zan-con .zan-contain{
+  display: flex;
+  justify-content: space-between;
+  flex-direction: column;
+}
+
+.zan-con .zan-contain p{
+  font-size: 2.25rem;
+}
+
+.zan-con .zan-contain p:first-child{
+  font-size: .875rem;
+  line-height: 1.5;
+}
+
+.zan-sub{
+  text-align: right;
+  margin-top: 1.25rem;
+  color: #a5a5a5;
+  font-size: .875rem;
+}
+
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+}
+
+
+.info-top{
+  padding: 20px 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px #a5a5a5 solid;
+}
+
+.o-span{
+  cursor: pointer;
+  color: rgb(7, 152, 244);
+}
+
+.e-pagination{
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 1.5625rem;
+}

+ 627 - 0
src/pages/editPages/cultural-relic/index.vue

@@ -0,0 +1,627 @@
+<!--  -->
+<template>
+  <div  v-loading.fullscreen.lock="loading"
+    element-loading-text="拼命加载中"
+    element-loading-spinner="el-icon-loading"
+    element-loading-background="rgba(0, 0, 0, 0.8)">
+    <main-top :crumb="crumbData"></main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="top-title">文物信息:</div>
+        <div class="form-con">
+          <el-form ref="form" :model="form" label-width="120px">
+            <el-form-item :rules="[
+              { required: true, message: '文物名称不能为空'}
+            ]" label="文物名称:" style="width:318px;">
+              <el-input v-model="form.name" placeholder="请输入文物名称"></el-input>
+            </el-form-item>
+
+            <el-form-item label="文物类别:" :rules="[
+              { required: true}
+            ]">
+              <el-select v-model="form.typeId" placeholder="请选择文物类别">
+                  <el-option v-for="(item,i) in plist" :key="i" :label="item.name" :value="item.id"></el-option>
+              </el-select>
+            </el-form-item>
+
+            <el-form-item label="分类年代:" :rules="[
+              { required: true}
+            ]">
+              <el-select v-model="form.timeId" placeholder="请选择分类年代" style="width:400px">
+                <el-option v-for="(item,i) in tlist" :key="i" :label="item.name" :value="item.id"></el-option>
+              </el-select>
+            </el-form-item>
+
+            <el-form-item label="文物年代:" >
+              <el-input v-model="form.typeTime" maxlength="50" show-word-limit placeholder="请输入文物年代"></el-input>
+            </el-form-item>
+
+            <el-form-item label="文物介绍:">
+                <vue-editor v-model="form.description" />
+            </el-form-item>
+
+            <el-form-item label="出土信息:" style="width:100%;">
+              <el-input v-model="form.venue" maxlength="50" show-word-limit placeholder="请输入出土信息"></el-input>
+            </el-form-item>
+
+             <el-form-item label="文物用途:" style="width:100%;">
+              <el-input v-model="form.purpose" maxlength="50" show-word-limit placeholder="请输入文物用途"></el-input>
+            </el-form-item>
+
+             <el-form-item label="文物材质:" style="width:100%;">
+              <el-input v-model="form.texture" maxlength="50" show-word-limit placeholder="请输入文物材质"></el-input>
+            </el-form-item>
+
+             <el-form-item label="文物尺寸:" style="width:100%;">
+              <el-input v-model="form.size" maxlength="50" show-word-limit placeholder="请输入文物尺寸"></el-input>
+            </el-form-item>
+
+            <el-form-item label="备注信息:" style="width:100%;">
+              <el-input v-model="form.remarks" maxlength="50" show-word-limit placeholder="请输入文物出土地点"></el-input>
+            </el-form-item>
+          </el-form>
+        </div>
+        <div class="top-title">展览信息:</div>
+        <div class="form-con">
+          <el-form ref="form" :model="form" label-width="120px">
+            <el-form-item label="文物展示方式:">
+                <el-radio-group v-model="form.type">
+                  <el-radio :label="'2D'" >2D</el-radio>
+                  <el-radio :label="'3D'" >3D</el-radio>
+                </el-radio-group>
+            </el-form-item>
+
+            <template v-if="form.type === '2D'">
+              <el-form-item label="轮播板式:">
+                <div class="banshi">
+                  <draggable v-model="uploadList" group="people" @start="drag=true" @end="drag=false">
+                    <div v-for="(item,i) in uploadList" :key="i"  class="imgdiv">
+                      <img v-if="item" :src="$serverName.replace('/zhoushan','') + item" alt="">
+                      <i class="el-icon-circle-close" @click.stop="delUploadItem(i)"></i>
+                    </div>
+                  </draggable>
+                </div>
+                <el-upload
+                  class="upload-demo"
+                  drag
+                  :on-success="upload_imglist_success"
+                  :action='uploadUrl'
+                  :headers="{
+                    token,
+                  }"
+                  :limit="10"
+                  :on-exceed="handleExceed"
+                  :before-upload="before_imglistUpload"
+                  multiple
+                  :show-file-list="false"
+                >
+                  <div>
+                    <i class="el-icon-upload"></i>
+                    <div class="el-upload__text">
+                      将文件拖到此处,或<em>点击上传</em>
+                    </div>
+                  </div>
+                  <div class="el-upload__tip" slot="tip">
+                    支持扩展名:.jpg, .jpgc, .png
+                  </div>
+                </el-upload>
+                <div class="el-upload__tip">*海报规定尺寸比例:3:4 </div>
+              </el-form-item>
+            </template>
+
+            <el-form-item v-else label="文物模型:" style="width:340px;">
+              <el-input v-model="form.modelUrl" placeholder="请输入文物模型链接(url地址)"></el-input>
+            </el-form-item>
+
+            <el-form-item label="展示封面:">
+               <Cropper
+                  :width="512"
+                  :height="512"
+                  :fixed-number="[1,1]"
+                  :uploadUrl = "'/exhibition/upload'"
+                  :img="form.pic"
+                  @clearImg="form.pic=''"
+                  @subUploadSucceed="getShopImages"
+              />
+              <span class="wwtxt" style="color:#C0C4CC">建议上传512*512的png格式图片</span>
+            </el-form-item>
+
+            <el-form-item label="文物展示:">
+               <el-upload
+                class="avatar-uploader"
+                :action="uploadUrl"
+                :headers="{
+                  token,
+                }"
+                :show-file-list="false"
+                :before-upload="beforeAvatarUpload"
+                :on-success="upload_avatar_success"
+                >
+                <img v-if="form.unityPic" :src="form.unityPic" class="avatar">
+                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              </el-upload>
+              <span class="wwtxt" style="color:#C0C4CC">仅支持上传文物展示的JPG格式文件</span>
+            </el-form-item>
+
+            <!-- <el-form-item label="四维模库:" style="width:340px;">
+              <el-button type="primary" @click="open">立即前往</el-button>
+            </el-form-item> -->
+
+            <el-form-item label="unity文件:">
+              <el-upload
+                class="upload-demo"
+                drag
+                :headers="{
+                  token
+                }"
+                :action="uploadUrl"
+                :file-list="unityUrlList"
+                :show-file-list="true"
+                :before-remove="beforeUnityUrlRemove"
+                :before-upload="beforeUnityUpload"
+                :on-success="upload_unity_success"
+              >
+                <div >
+                  <i class="el-icon-upload"></i>
+                  <div class="el-upload__text">
+                    将文件拖到此处,或
+                    <em>点击上传</em>
+                  </div>
+                </div>
+                <div class="el-upload__tip" slot="tip">支持上传unity文件:.unity, .ab, .u3d</div>
+              </el-upload>
+            </el-form-item>
+
+            <el-form-item label="视频动画:">
+              <el-upload
+                class="upload-demo"
+                drag
+                :headers="{
+                  token
+                }"
+                :file-list="contentUrlList"
+                :show-file-list="true"
+                :action="uploadUrl"
+                :before-remove="beforeRemove"
+                :before-upload="beforeUpload"
+                :on-success="upload_success"
+              >
+                <div>
+                  <i class="el-icon-upload"></i>
+                  <div class="el-upload__text">
+                    将文件拖到此处,或
+                    <em>点击上传</em>
+                  </div>
+                </div>
+                <div class="el-upload__tip" slot="tip">支持视频动画格式:.wma, .wav, .mp4</div>
+              </el-upload>
+            </el-form-item>
+            <el-form-item label="二维码信息:">
+               <el-upload
+                class="avatar-uploader"
+                :action="uploadUrl"
+                :headers="{
+                  token,
+                }"
+                :show-file-list="false"
+                :before-upload="beforeqrCodeUpload"
+                :on-success="upload_qrCode_success"
+                >
+                <div v-if="form.qrCode" class="imgdiv">
+                  <img
+                    style="width: 100%;height:100%;"
+                    :src="$serverName.replace('/zhoushan','') + form.qrCode"
+                  >
+                  <i class="el-icon-circle-close" @click.stop="form.qrCode=''"></i>
+                </div>
+                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              </el-upload>
+
+            </el-form-item>
+            <el-form-item label="是否展示:">
+              <el-radio-group v-model="form.state">
+                <el-radio :label="0" >是</el-radio>
+                <el-radio :label="1" >否</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-form>
+        </div>
+        <el-button type="primary" @click="onSubmit">发布</el-button>
+        <el-button @click="$router.back()">取消</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+import { VueEditor } from 'vue2-editor'
+import Cropper from '@/components/cropper'
+import draggable from 'vuedraggable'
+
+let urlType = {
+  0: '/collection/addCollection',
+  1: '/collection/updateCollection'
+}
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+    VueEditor,
+    Cropper,
+    draggable
+  },
+  data () {
+    let crumbData = [
+      {
+        name: '文物库',
+        id: 0
+      },
+      {
+        name: this.$route.params.type ? '编辑文物' : '新增文物',
+        id: 1
+      }
+    ]
+    return {
+      uploadList: [],
+      crumbData,
+      loading: false,
+      contentUrlList: [],
+      unityUrlList: [],
+      form: {
+        name: '',
+        typeId: 2,
+        timeId: 1,
+        typeTime: '',
+        num: '',
+        discoveryTime: '',
+        venue: '',
+        modelUrl: '',
+        pic: '',
+        qrCode: '',
+        contentUrl: '',
+        unityPic: '',
+        unityUrl: '',
+        description: '',
+        purpose: '',
+        remarks: '',
+        repairTime: '',
+        size: '',
+        start: 0,
+        state: 0,
+        texture: '',
+        type: '2D',
+        typeImages: ''
+      },
+      plist: [],
+      tlist: [],
+      realType: '',
+      token: window.localStorage.getItem('token'),
+      uploadUrl: `${this.$serverName}/collection/upload`,
+      type: this.$route.params.type
+    }
+  },
+  watch: {
+
+  },
+  methods: {
+    delUploadItem (i) {
+      this.uploadList.splice(i, 1)
+    },
+    getShopImages (img) {
+      this.form.pic = img
+    },
+    getQrCodeImages (img) {
+      this.form.qrCode = img
+      console.log(this.form.qrCode)
+    },
+    getModelImages (img) {
+      this.form.unityPic = img
+    },
+    handleExceed (files, fileList) {
+      this.$message.warning(`上传数量超出限制`)
+    },
+    before_imglistUpload () {
+      this.loading = true
+    },
+    upload_imglist_success (data) {
+      this.loading = false
+      this.uploadList.push(data.data)
+    },
+    onSubmit () {
+      let {name,
+        typeId,
+        type,
+        timeId,
+        typeTime,
+        purpose,
+        num,
+        discoveryTime,
+        repairTime,
+        venue,
+        modelUrl,
+        pic,
+        qrCode,
+        contentUrl,
+        size,
+        typeImages,
+        unityPic,
+        texture,
+        unityUrl,
+        state,
+        remarks,
+        description,
+        id} = this.form
+      contentUrl = this.contentUrlList[0] ? this.contentUrlList[0].url : ''
+      unityUrl = this.unityUrlList[0] ? this.unityUrlList[0].url : ''
+      if (type === '2D') {
+        typeImages = this.uploadList
+      }
+      let data = {name,
+        typeId,
+        timeId,
+        typeTime,
+        num,
+        discoveryTime,
+        repairTime,
+        typeImages,
+        type,
+        size,
+        venue,
+        modelUrl,
+        unityPic,
+        unityUrl,
+        texture,
+        remarks,
+        purpose,
+        pic,
+        qrCode,
+        contentUrl,
+        state,
+        description}
+      if (this.type) {
+        data['id'] = id
+      }
+      this.$http.post(urlType[this.type], data).then(res => {
+        if (res.code === 0) {
+          this.$alert(this.$route.params.type ? '操作成功' : '操作成功', '提示', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.$router.back()
+            }
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    open () {
+      window.open('https://www.4dmodel.com', '_blank')
+    },
+
+    beforeAvatarUpload (file) {
+      this.loading = true
+      let typeArr = ['jpg']
+      let type = this.isTypeBySend(file.name, typeArr)
+      if (!type) {
+        this.loading = false
+        this.$message.error('仅支持上传文物展示的JPG格式文件')
+        return type
+      }
+    },
+
+    beforeUnityUpload (file) {
+      this.loading = true
+      let typeArr = ['unity', 'ab', 'u3d']
+      let type = this.isTypeBySend(file.name, typeArr)
+      if (!type) {
+        this.loading = false
+        this.$message.error('支持上传unity文件:.unity, .ab, .u3d')
+        return type
+      }
+    },
+
+    beforeUnityUrlRemove (file) {
+      this.unityUrlList = []
+    },
+
+    beforeRemove (file) {
+      this.contentUrlList = []
+    },
+
+    beforeUpload (file) {
+      this.loading = true
+      let typeArr = ['wma', 'wav', 'mp4']
+      let type = this.isTypeBySend(file.name, typeArr)
+      if (!type) {
+        this.loading = false
+        this.$message.error('支持视频动画格式:.wma, .wav, .mp4')
+        return type
+      }
+    },
+
+    beforeqrCodeUpload () {
+      this.loading = true
+    },
+    upload_qrCode_success (data) {
+      this.loading = false
+      this.form.qrCode = data.data
+    },
+    upload_avatar_success (data) {
+      this.loading = false
+      this.form.unityPic = data.data
+    },
+
+    upload_unity_success (data) {
+      this.loading = false
+      this.form.unityUrl = data.data
+      this.unityUrlList = [{
+        name: data.data.split('/')[data.data.split('/').length - 1],
+        url: data.data
+      }]
+    },
+
+    upload_success (data) {
+      this.loading = false
+      this.form.contentUrl = data.data
+      this.contentUrlList = [{
+        name: data.data.split('/')[data.data.split('/').length - 1],
+        url: data.data
+      }]
+    },
+
+    async getPositionList () {
+      let result = await this.$http({
+        method: 'post',
+        data: {
+          state: 0
+        },
+        url: '/collection/typeList'
+      })
+
+      this.plist = result.data
+    },
+    async getTypeList () {
+      let result = await this.$http({
+        method: 'post',
+        url: '/collection/timeList'
+      })
+
+      this.tlist = result.data
+    }
+
+  },
+  mounted () {
+    this.getPositionList()
+    this.getTypeList()
+    if (this.type) {
+      let info = window.localStorage.getItem('editCollection')
+      if (info) {
+        this.form = JSON.parse(info)
+        this.form.typeId = Number(this.form.typeId)
+        this.form.equipmentId = Number(this.form.equipmentId)
+        this.form.state = Number(this.form.state)
+        let unityUrl = this.form.unityUrl
+        let contentUrl = this.form.contentUrl
+
+        if (unityUrl) {
+          this.unityUrlList = [{
+            name: unityUrl.split('/')[unityUrl.split('/').length - 1],
+            url: unityUrl
+          }]
+        }
+
+        if (contentUrl) {
+          this.contentUrlList = [{
+            name: contentUrl.split('/')[contentUrl.split('/').length - 1],
+            url: contentUrl
+          }]
+        }
+        setTimeout(() => {
+          this.uploadList = this.form.typeImages ? JSON.parse(this.form.typeImages) : []
+        })
+      }
+    } else {
+      this.form = {
+        name: '',
+        typeId: 2,
+        timeId: 1,
+        typeTime: '',
+        num: '',
+        discoveryTime: '',
+        venue: '',
+        modelUrl: '',
+        pic: '',
+        qrCode: '',
+        contentUrl: '',
+        unityPic: '',
+        unityUrl: '',
+        description: '',
+        purpose: '',
+        remarks: '',
+        repairTime: '',
+        size: '',
+        start: 0,
+        state: 0,
+        texture: '',
+        type: '2D',
+        typeImages: ''
+      }
+    }
+  }
+}
+</script>
+
+<style lang='less' scoped>
+/* 引入公共css类 */
+@import './style.less';
+</style>
+
+<style>
+.ql-picker-label {
+  line-height: 1;
+  overflow: hidden;
+}
+
+.avatar-uploader .el-upload {
+  /* border: 1px dashed #000; */
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+.ql-picker-label {
+  line-height: 1;
+  overflow: hidden;
+}
+
+.avatar-uploader{
+  border: 1px dashed #ccc;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+  width: 178px;
+  margin-top: 10px;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px!important;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+
+</style>

+ 53 - 0
src/pages/editPages/cultural-relic/style.less

@@ -0,0 +1,53 @@
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+
+
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+}
+
+.top-body .top-title{
+  font-weight: bold;
+  font-size: 16px;
+  margin-bottom: 20px;
+}
+
+.form-con{
+  width: 85%;
+  border: 1px solid #e5e5e5;
+  padding: 2% 10% 2% 2%;
+  margin-bottom: 20px;
+}
+.banshi{
+  line-height: 1;
+  font-size: 0;
+  >div{
+    display: flex;
+    margin-bottom: 10px;
+    flex-wrap: wrap;
+    >div{
+      width: 19%;
+      border: 1px solid #ccc;
+      min-height: 100px;
+      margin-right: 4px;
+      margin-bottom: 20px;
+      >img{
+        cursor: pointer;
+        width: 100%;
+      }
+      &:last-of-type{
+        margin-right: 0;
+      }
+    }
+  }
+}

+ 442 - 0
src/pages/editPages/display/index.vue

@@ -0,0 +1,442 @@
+<!--  -->
+<template>
+  <div v-loading.fullscreen.lock="loading"
+    element-loading-text="拼命加载中"
+    element-loading-spinner="el-icon-loading"
+    element-loading-background="rgba(0, 0, 0, 0.8)">
+    <main-top :crumb="crumbData"></main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="top-title">方案信息:</div>
+        <div class="form-con">
+          <el-form ref="form" :model="form" label-width="100px">
+            <el-form-item label="方案名称:" style="width:318px;">
+              <el-input v-model="form.name"></el-input>
+            </el-form-item>
+
+            <el-form-item label="展示说明:">
+              <vue-editor v-model="form.description" />
+            </el-form-item>
+
+            <el-form-item></el-form-item>
+          </el-form>
+        </div>
+        <div class="top-title">展示信息:</div>
+        <div class="form-con">
+          <el-form ref="form" :model="form" label-width="100px">
+            <el-form-item label="展示类别:" style="width:318px;">
+              <el-select v-model="form.typeId" placeholder="请选择文物类别">
+                <el-option v-for="(item,i) in exhibitionlist" :key="i" :label="item.name" :value="item.id"></el-option>
+              </el-select>
+            </el-form-item>
+
+            <el-form-item label="展示封面:">
+               <el-upload
+                class="avatar-uploader"
+                :action="uploadUrl"
+                :headers="{
+                  token,
+                }"
+                :show-file-list="false"
+                :before-upload="beforeUpload"
+                :on-success="upload_avatar_success"
+                >
+                <img v-if="form.webUrl" :src="form.webUrl" class="avatar">
+                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              </el-upload>
+
+            </el-form-item>
+
+            <el-form-item label="展示文物:">
+              <el-table :data="tableData" v-if="tableData.length>0" style="width: 100%">
+                <el-table-column
+                  v-for="(item, idx) in data"
+                  :key="idx"
+                  :prop="item.prop"
+                  :label="item.label"
+                >
+                  <template slot-scope="scope">
+                    <span>{{scope.row[item.prop]}}</span>
+                  </template>
+                </el-table-column>
+                <el-table-column label="操作">
+                  <template slot-scope="scope">
+                    <span class="o-span" @click="del(scope.row)">删除</span>
+                  </template>
+                </el-table-column>
+              </el-table>
+              <div @click="getInformation" class="avatar-uploader">
+                <i class="el-icon-plus avatar-uploader-icon"></i>
+                <span class="wwtxt">文物库</span>
+              </div>
+            </el-form-item>
+            <el-form-item label="是否启用:">
+              <el-radio-group v-model="form.state">
+                <el-radio :label="0">是</el-radio>
+                <el-radio :label="1">否</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-form>
+        </div>
+        <el-button type="primary" @click="onSubmit">发布</el-button>
+        <el-button @click="$router.back()">取消</el-button>
+      </div>
+      <div @click="showSelect=false" class="select-hover" v-if="showSelect">
+        <div @click.stop class="select-con">
+          <div class="info-left">
+            <span>按文物类别查看:</span>
+            <el-select style="width:100px;" v-model="typeId" placeholder="请选择">
+              <el-option label="全部" value=""></el-option>
+              <el-option v-for="(item,i) in tlist" :key="i" :label="item.name" :value="item.id"></el-option>
+            </el-select>
+            <span style="margin-left:20px;">按文物年代查看:</span>
+            <el-select style="width:100px;" v-model="timeId" placeholder="请选择">
+              <el-option label="全部" value=""></el-option>
+              <el-option v-for="(item,i) in timelist" :key="i" :label="item.name" :value="item.id"></el-option>
+            </el-select>
+            <el-input style="width:220px;margin:0 20px;" v-model="inputKey" placeholder="请输入文物名称搜索"></el-input>
+            <el-button type="primary" @click="getInformation">查找</el-button>
+            <el-button @click="inputKey=''">重置</el-button>
+          </div>
+          <ul>
+            <li :class="{'active':isSelect(item,i)}" @click="pushIn(item)" v-for="(item,i) in collectList" :key="i">
+              <div class="mask">
+                <!-- <div>{{1}}</div> -->
+              </div>
+              <div class="li-img">
+                <img :src="item.pic" alt />
+                <div><span>浏览量: {{Math.round(Math.random()*100000)}}</span> 点赞数: {{Math.round(Math.random()*1000)}}</div>
+              </div>
+              <div>{{item.timeName}} {{item.typeName}}</div>
+              <p>{{item.name}}</p>
+            </li>
+          </ul>
+          <div class="save-btn">
+            <el-button type="primary" @click="showSelect=false">确定</el-button>
+            <el-button @click="()=>{showSelect=false}">取消</el-button>
+          </div>
+        </div>
+      </div>
+
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+import SearchBar from '@/components/search-bar'
+import Cropper from '@/components/cropper'
+
+import { VueEditor } from 'vue2-editor'
+
+let urlType = {
+  0: '/exhibition/addExhibition',
+  1: '/exhibition/updateExhibition'
+}
+
+let urlType1 = {
+  0: '/exhibition/insertExhibitionCollection',
+  1: '/exhibition/updateExhibitionCollection'
+}
+
+let data = [
+  {
+    prop: 'idx',
+    label: '序号'
+  },
+  {
+    prop: 'name',
+    label: '文物名称'
+  },
+  {
+    prop: 'typeName',
+    label: '文物类别'
+  },
+  {
+    prop: 'timeName',
+    label: '文物年代'
+  }
+]
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+    VueEditor,
+    SearchBar,
+    Cropper
+  },
+  data () {
+    let crumbData = [
+      {
+        name: '展示管理',
+        id: 0
+      },
+      {
+        name: this.$route.params.type ? '编辑方案' : '新增方案',
+        id: 1
+      }
+    ]
+    return {
+      crumbData,
+      data,
+      plist: [],
+      tlist: [],
+      exhibitionlist: [],
+      showSelect: false,
+      content: '<h1>Some initial content</h1>',
+      form: {
+        name: '',
+        typeId: 3,
+        equipmentId: 1,
+        state: 0,
+        description: '',
+        webUrl: ''
+      },
+      tableData: [],
+      collectList: [],
+      timelist: [],
+      typeId: '',
+      timeId: '',
+      inputKey: '',
+      type: this.$route.params.type,
+      id: this.$route.params.id,
+      loading: false,
+      token: window.localStorage.getItem('token'),
+      uploadUrl: `${this.$serverName}/exhibition/upload`
+    }
+  },
+  watch: {
+    inputKey () {
+      this.refresh()
+    },
+    tableData (newVal) {
+      newVal.forEach((item, i) => {
+        item.idx = i + 1
+      })
+    }
+  },
+  methods: {
+    beforeUpload () {
+      this.loading = true
+    },
+    upload_avatar_success (data) {
+      this.loading = false
+      this.form.webUrl = data.data
+    },
+
+    refresh () {
+      this.loading = true
+      this.getInformation()
+      this.loading = false
+    },
+    async getPositionList () {
+      let result = await this.$http({
+        method: 'post',
+        url: '/position/list'
+      })
+
+      this.plist = result.data
+    },
+    async getcollectList () {
+      let result = await this.$http({
+        method: 'post',
+        data: {
+          state: 0
+        },
+        url: '/collection/typeList'
+      })
+      this.tlist = result.data
+
+      this.form.typeId = this.tlist[0].id
+      let result1 = await this.$http({
+        method: 'post',
+        url: '/collection/timeList'
+      })
+      this.timelist = result1.data
+
+      let result2 = await this.$http({
+        method: 'post',
+        url: '/exhibition/typeList'
+      })
+      this.exhibitionlist = result2.data
+    },
+    async getexhibitionList (exhibitionId) {
+      let result = await this.$http({
+        method: 'post',
+        data: {
+          exhibitionId: Number(exhibitionId)
+        },
+        url: '/exhibition/findCollectionByExhibition'
+      })
+
+      this.tableData = result.data
+      console.log('tableData', result.data)
+
+      this.tableData.forEach((item, i) => {
+        item.idx = i + 1
+      })
+    },
+    isSelect (item, idx) {
+      if (this.tableData.length > 0) {
+        for (let i = 0; i < this.tableData.length; i++) {
+          let sub = this.tableData[i]
+          if (sub.id === item.id) {
+            return true
+          }
+        }
+      }
+      return false
+    },
+    onSubmit () {
+      let { name, id, typeId, equipmentId, state, description, webUrl } = this.form
+      let data = { name, typeId, equipmentId, state, description, webUrl }
+      if (this.type) {
+        data['id'] = id
+      }
+      this.$http.post(urlType[this.type], data).then(res => {
+        if (res.code === 0) {
+          console.log(res)
+          let exhibitionId = res.data.id
+
+          let collectionId = []
+
+          this.tableData.forEach(sub => {
+            collectionId.push(sub.id)
+          })
+          let params = {
+            exhibitionId,
+            collectionId: collectionId.join(',')
+          }
+          this.$http.post(urlType1[this.type], params).then(res => {
+            if (res.code === 0) {
+              this.$alert('操作成功', '提示', {
+                confirmButtonText: '确定',
+                callback: action => {
+                  this.$router.back()
+                }
+              })
+            } else {
+              this.$notify.error({
+                title: '错误',
+                message: res.message
+              })
+            }
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+
+    pushIn (item) {
+      for (let i = 0; i < this.tableData.length; i++) {
+        let sub = this.tableData[i]
+        if (sub.id === item.id) {
+          return this.tableData.splice(i, 1)
+        }
+      }
+      this.tableData.push(item)
+    },
+    del (item) {
+      let arr = []
+      this.tableData.forEach(sub => {
+        if (sub.id !== item.id) {
+          arr.push(sub)
+        }
+      })
+
+      this.tableData = arr
+    },
+    async getInformation () {
+      this.showSelect = true
+      let params = {
+        name: this.inputKey,
+        typeId: this.typeId,
+        timeId: this.timeId,
+        pageNum: 1,
+        pageSize: 180
+      }
+
+      let result = await this.$http({
+        method: 'post',
+        data: params,
+        url: '/collection/list'
+      })
+
+      if (result.code !== 0) {
+        return
+      }
+      this.collectList = result.data.list
+    },
+    async getDetail () {
+      let result = await this.$http({
+        method: 'post',
+        headers: {
+          token: window.localStorage.getItem('token')
+        },
+        url: `/exhibition/getExhibitionById`,
+        data: {
+          id: Number(this.id)
+        }
+      })
+
+      this.form = result.data
+      this.tableData = result.data.collectionList
+    }
+  },
+
+  mounted () {
+    this.getcollectList()
+    this.getPositionList()
+    if (this.id && this.id !== 'none') {
+      this.getDetail()
+      // this.getexhibitionList(this.id)
+    }
+  }
+}
+</script>
+
+<style scoped>
+/* 引入公共css类 */
+@import url(./style);
+</style>
+
+<style>
+.ql-picker-label {
+  line-height: 1;
+  overflow: hidden;
+}
+
+.avatar-uploader{
+  border: 1px dashed #ccc;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+  width: 178px;
+  margin-top: 10px;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px!important;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+
+</style>

+ 136 - 0
src/pages/editPages/display/style.css

@@ -0,0 +1,136 @@
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+}
+
+.top-body .top-title{
+  font-weight: bold;
+  font-size: 16px;
+  margin-bottom: 20px;
+}
+
+.form-con{
+  width: 85%;
+  border: 1px solid #e5e5e5;
+  padding: 2% 10% 2% 2%;
+  margin-bottom: 20px;
+}
+.select-hover{
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.1);
+  position: fixed;
+  top: 0;
+  left: 0;
+  z-index: 999;
+}
+
+.select-con{
+  width: 51%;
+  overflow: auto;
+  max-height: 80%;
+  background: #fff;
+  position: absolute;
+  top: 53%;
+  left: 50%;
+  transform: translate(-30%,-50%);
+  padding: 20px;
+}
+
+
+.select-con ul{
+  display: flex;
+  flex-wrap: wrap;
+  margin: 20px 0;
+}
+
+.select-con ul li {
+  width: 22%;
+  margin-right: 1%;
+  cursor: pointer;
+  font-size: .8rem;
+  padding: 0.5%;
+  color: #2d2d2d;
+  margin-bottom: 20px;
+  border: 1px solid rgba(0, 0, 0, 0);
+  position: relative;
+}
+
+.select-con ul .active {
+}
+
+.select-con ul .active .mask{
+  width: 100%;
+  position: absolute;
+  left: 0;
+  top: 0;
+  height: 100%;
+  background: rgba(98, 82, 27, 0.5);
+  margin: 0;
+  z-index: 999;
+}
+
+.select-con ul .active .mask div{
+  position: absolute;
+  left: 50%;
+  top: 50%;
+  transform: translate(-50%,-50%);
+  color: #fff;
+  font-weight: bold;
+  font-size: 28px;
+}
+
+
+.select-con ul img {
+  width: 100%;
+}
+
+.select-con ul div {
+  margin: 5px 0;
+}
+
+.save-btn{
+  margin: 0 20px 20px;
+}
+
+.select-con ul .li-img {
+  position: relative;
+}
+.select-con ul .li-img div{
+  position: absolute;
+  left: 5px;
+  bottom: 5px;
+  font-size: 0.5rem;
+  color: #fff;
+}
+
+.select-con ul .li-img div span{
+  margin-right: 10px;
+}
+
+
+.select-con ul img {
+  width: 100%;
+}
+
+.wwtxt{
+  text-align: center;
+  width: 100%;
+  display: inline-block;
+  position: absolute;
+  left: 0;
+  bottom: 20px;
+  color: #777;
+}

+ 379 - 0
src/pages/editPages/message/index.vue

@@ -0,0 +1,379 @@
+<!--  -->
+<template>
+  <div v-loading.fullscreen.lock="loading"
+    element-loading-text="拼命加载中"
+    element-loading-spinner="el-icon-loading"
+    element-loading-background="rgba(0, 0, 0, 0.8)">
+    <main-top :crumb="crumbData"></main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <el-form ref="form" :model="form" label-width="100px">
+          <el-form-item label="资讯名称:" style="width:318px;">
+            <el-input v-model="form.name"></el-input>
+          </el-form-item>
+          <el-form-item label="资讯类型:">
+            <el-select v-model="form.type" placeholder="请选择资讯类型">
+              <el-option label="海报轮播" :value="0"></el-option>
+              <el-option label="视频轮播" :value="1"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="轮播时间:" style="width:518px;">
+            <el-date-picker
+              v-model="form.date"
+              type="daterange"
+              @change="handleChange"
+              value-format="timestamp"
+              range-separator="-"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+            >
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item label="资讯说明:">
+            <vue-editor v-model="form.description" />
+          </el-form-item>
+          <template v-if="form.type === 0">
+            <el-form-item label="轮播板式:">
+              <el-radio-group v-model="form.contentNum" @change="handleRadio">
+                <el-radio v-for="(item,i) in banshi"  :key="i" :label="item.size">{{item.size}}</el-radio>
+              </el-radio-group>
+              <div class="banshi">
+                <draggable v-model="uploadList" group="people" @start="drag=true" @end="drag=false">
+                  <div v-for="(element,i) in radioActive.arr" :key="i">
+                    <img v-if="uploadList[i]" :src="$serverName.replace('/zhoushan','') + uploadList[i]" alt="">
+                  </div>
+                </draggable>
+              </div>
+              <el-upload
+                class="upload-demo"
+                drag
+                :on-success="upload_success"
+                :action='uploadUrl'
+                :headers="{
+                  token,
+                }"
+                :limit="form.contentNum"
+                :on-exceed="handleExceed"
+                :before-upload="beforeUpload"
+                multiple
+                :show-file-list="false"
+              >
+                <div>
+                  <i class="el-icon-upload"></i>
+                  <div class="el-upload__text">
+                    将文件拖到此处,或<em>点击上传</em>
+                  </div>
+                </div>
+                <div class="el-upload__tip" slot="tip">
+                  支持扩展名:.jpg, .jpgc, .png
+                </div>
+              </el-upload>
+              <div class="el-upload__tip">*海报规定尺寸: {{radioActive.dec}}</div>
+            </el-form-item>
+          </template>
+
+          <template v-if="form.type === 1">
+            <el-form-item label="轮播内容:">
+              <el-upload
+                class="upload-demo"
+                drag
+                :on-success="upload_success"
+                :action='uploadUrl'
+                :before-upload="beforeUpload"
+                :headers="{
+                  token,
+                }"
+                multiple
+              >
+                <img
+                  style="width:100%"
+                  v-if="form.contentUrl"
+                  :src="form.contentUrl"
+                  alt=""
+                />
+                <div v-else>
+                  <i class="el-icon-upload"></i>
+                  <div class="el-upload__text">
+                    将文件拖到此处,或<em>点击上传</em>
+                  </div>
+                </div>
+                <div class="el-upload__tip" slot="tip">
+                  支持扩展名:.wma, .rmvb, .rm, .flash, .mp4
+                </div>
+              </el-upload>
+            </el-form-item>
+          </template>
+
+          <el-form-item label="展示顺序:">
+            <el-input-number
+              v-model="form.orderNum"
+              :min="1"
+              :max="1000"
+              label="展示顺序"
+            ></el-input-number>
+          </el-form-item>
+          <el-form-item label="是否启用:">
+            <el-radio-group v-model="form.state">
+              <el-radio :label="0">是</el-radio>
+              <el-radio :label="1">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="预览效果:">
+            <el-button @click="dialogTableVisible = true">点击查看</el-button>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="onSubmit">发布</el-button>
+            <el-button @click="$router.back()">取消</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+      <el-dialog title="预览效果" :visible.sync="dialogTableVisible">
+           <video
+              controls="controls"
+              v-if="form.type === 1"
+              autoplay
+              :src="$serverName.replace('/zhoushan','') + form.contentUrl"
+              style="width:100%"
+            ></video>
+          <div class="showImg" v-else>
+            <div v-for="(item,i) in uploadList" :key="i">
+              <img :src="$serverName.replace('/zhoushan','') + item" alt="">
+            </div>
+          </div>
+      </el-dialog>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+import { VueEditor } from 'vue2-editor'
+import draggable from 'vuedraggable'
+let urlType = {
+  0: '/information/addInformation',
+  1: '/information/updateInformation'
+}
+
+let banshi = [{
+  size: 1,
+  dec: '8640*1920'
+}, {
+  size: 2,
+  dec: '4320*1920'
+}, {
+  size: 4,
+  dec: '2160*1920'
+}, {
+  size: 6,
+  dec: '1440*1920'
+}, {
+  size: 8,
+  dec: '1080*1920'
+}]
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+    VueEditor,
+    draggable
+  },
+  data () {
+    let crumbData = [
+      {
+        name: '资讯管理',
+        id: 0
+      },
+      {
+        name: this.$route.params.type ? '编辑资讯' : '发布资讯',
+        id: 0
+      }
+    ]
+    return {
+      mediatype: '',
+      crumbData,
+      content: '<h1>Some initial content</h1>',
+      banshi,
+      loading: false,
+      form: {
+        name: '',
+        type: 0,
+        startTime: '',
+        endTime: '',
+        date: [],
+        description: '',
+        contentUrl: '',
+        orderNum: 1,
+        state: 0,
+        id: '',
+        contentNum: 4
+      },
+      dialogTableVisible: false,
+      type: this.$route.params.type,
+      radioActive: [],
+      uploadUrl: `${this.$serverName}/exhibition/upload`,
+      token: window.localStorage.getItem('token'),
+      uploadList: []
+    }
+  },
+  watch: {
+    'form.contentUrl': {
+      immediate: true,
+      handler: function () {
+        this.mediatype = this.getType()
+      }
+    },
+    'form.contentNum': {
+      immediate: true,
+      handler: function (newVal) {
+        let tmp = banshi.filter(item => item.size === newVal) || ''
+        this.radioActive = {
+          dec: tmp[0].dec,
+          arr: new Array(tmp[0].size)
+        }
+        this.uploadList = []
+      }
+    }
+  },
+
+  methods: {
+    handleRadio (type) {
+      console.log(type)
+    },
+    getType () {
+      if (!this.form.contentUrl) {
+        return null
+      }
+      let type = this.form.contentUrl.split('.')
+      type = type[type.length - 1]
+      var a = [
+        'cd',
+        'ogg',
+        'mp3',
+        'asf',
+        'wma',
+        'wav',
+        'mp3pro',
+        'rm',
+        'real',
+        'ape',
+        'module',
+        'midi',
+        'vqf'
+      ]
+      var v = ['jpg', 'jpgc', 'png']
+      var m = ['wma', 'rmvb', 'rm', 'flash', 'mp4']
+
+      for (var i in a) {
+        if (a[i] === type.toLowerCase()) return 'audio'
+      } // 音频
+      for (var j in v) {
+        if (v[j] === type.toLowerCase()) return 'picture'
+      } // 图片
+      for (var k in m) {
+        if (m[k] === type.toLowerCase()) return 'video'
+      } // 图片
+
+      return null
+    },
+    onSubmit () {
+      let {
+        type,
+        id,
+        name,
+        contentUrl,
+        orderNum,
+        state,
+        startTime,
+        endTime,
+        description,
+        contentNum
+      } = this.form
+      if (type === 0) {
+        contentUrl = this.uploadList
+      }
+      let data = {
+        name,
+        type: Number(type),
+        contentUrl,
+        orderNum,
+        contentNum,
+        state,
+        startTime,
+        endTime,
+        description
+      }
+      if (this.type) {
+        data['id'] = id
+      }
+      this.$http.post(urlType[this.type], data).then(res => {
+        if (res.code === 0) {
+          this.$alert('操作成功', '提示', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.$router.back()
+            }
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+
+    handleChange (data) {
+      this.form.startTime = data[0]
+      this.form.endTime = data[1]
+    },
+
+    handleExceed (files, fileList) {
+      this.$message.warning(`当前限制选择 ${this.radio} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`)
+    },
+    beforeUpload () {
+      this.loading = true
+    },
+    upload_success (data) {
+      this.loading = false
+      if (this.form.type === 0) {
+        this.uploadList.push(data.data)
+      } else {
+        this.form.contentUrl = data.data
+      }
+    }
+  },
+  mounted () {
+    if (this.type) {
+      let info = window.localStorage.getItem('editInfo')
+      if (info) {
+        this.form = JSON.parse(info)
+        this.form.state = Number(this.form.state || 0)
+
+        this.form.date = [
+          Number(this.form.startTime),
+          Number(this.form.endTime)
+        ]
+        setTimeout(() => {
+          this.uploadList = this.form.contentUrl ? JSON.parse(this.form.contentUrl) : []
+        })
+      }
+    }
+  }
+}
+</script>
+
+<style lang='less' scoped>
+/* 引入公共css类 */
+@import './style.less';
+</style>
+
+<style>
+.ql-picker-label {
+  line-height: 1;
+  overflow: hidden;
+}
+</style>

+ 54 - 0
src/pages/editPages/message/style.less

@@ -0,0 +1,54 @@
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 1.25rem 10%;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+}
+
+.top-body .top-con{
+  font-weight: bold;
+}
+.showImg{
+  display: flex;
+  justify-content: space-between;
+  width: 100%;
+  >div{
+    flex: 1;
+    >img{
+      width: 100%;
+    }
+  }
+}
+.banshi{
+  line-height: 1;
+  font-size: 0;
+  >div{
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 10px;
+    >div{
+      flex: 1;
+      border: 1px solid #ccc;
+      min-height: 100px;
+      width: calc(100% - 2px);
+      margin-right: 2px;
+      >img{
+        cursor: pointer;
+        width: 100%;
+      }
+      &:last-of-type{
+        margin-right: 0;
+      }
+    }
+  }
+}

+ 117 - 0
src/pages/editPages/questionnaire/index.vue

@@ -0,0 +1,117 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData"></main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <el-form ref="form" :model="form" label-width="100px">
+          <el-form-item label="问卷名称:" style="width:318px;">
+            <el-input v-model="form.name" placeholder="请输入问卷名称"></el-input>
+          </el-form-item>
+          <el-form-item label="问卷说明:">
+            <vue-editor v-model="content" />
+          </el-form-item>
+          <el-form-item label="问题1:" style="width:408px;">
+            <el-input v-model="form.name" placeholder="请输入问题"></el-input>
+            <div class="q-item">
+              <el-label>问题描述:</el-label>
+              <el-radio-group v-model="form.resource">
+                <el-radio label="单选"></el-radio>
+                <el-radio label="多选"></el-radio>
+                <el-radio label="问答"></el-radio>
+              </el-radio-group>
+              <el-label>必选:</el-label>
+              <el-radio-group v-model="form.resource">
+                <el-radio label="是"></el-radio>
+                <el-radio label="否"></el-radio>
+              </el-radio-group>
+              <el-label>选项:</el-label>
+              <div class="slt-item">
+                <el-input v-model="form.name" placeholder="选项1(必填)"></el-input>
+              </div>
+              <div class="slt-item">
+                <el-input v-model="form.name" placeholder="选项2(必填)"></el-input>
+              </div>
+            <el-button>添加选项</el-button>
+            </div>
+            <el-button>添加问题</el-button>
+
+          </el-form-item>
+          <el-form-item label="截止时间:" style="width:518px;">
+            <el-date-picker
+              v-model="form.date1"
+              type="date"
+              placeholder="选择日期">
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="onSubmit">发布</el-button>
+            <el-button @click="$router.back()">取消</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+import SearchBar from '@/components/search-bar'
+import { VueEditor } from 'vue2-editor'
+
+const crumbData = [
+  {
+    name: '消息管理',
+    id: 0
+  },
+  {
+    name: '发布资讯',
+    id: 0
+  }
+]
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+    VueEditor,
+    SearchBar
+  },
+  data () {
+    return {
+      crumbData,
+      content: '<h1>Some initial content</h1>',
+      form: {
+        name: '',
+        region: '',
+        date1: '',
+        date2: '',
+        delivery: false,
+        type: [],
+        resource: '',
+        desc: ''
+      }
+    }
+  },
+  methods: {
+    onSubmit () {
+      console.log('submit!')
+    }
+  }
+}
+</script>
+
+<style scoped>
+/* 引入公共css类 */
+@import url(./style);
+</style>
+
+<style>
+.ql-picker-label {
+  line-height: 1;
+  overflow: hidden;
+}
+</style>

+ 30 - 0
src/pages/editPages/questionnaire/style.css

@@ -0,0 +1,30 @@
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 1.25rem 10%;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+}
+
+.top-body .top-con{
+  font-weight: bold;
+}
+
+
+.slt-item{
+  margin-bottom: 10px;
+}
+
+.q-item{
+  margin-left: 20px;
+  margin-bottom: 20px;
+}

+ 342 - 0
src/pages/editPages/role/index.vue

@@ -0,0 +1,342 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData"></main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="top-title">角色信息:</div>
+        <div class="form-con">
+          <el-form :disabled="$route.params.type === 2" ref="roleform" :rules="rules" :model="form" label-width="100px">
+            <el-form-item label="角色名称:" style="width:318px;">
+              <el-input v-model="form.roleName" maxlength="15" show-word-limit></el-input>
+            </el-form-item>
+            <el-form-item label="角色说明:">
+              <el-input type="textarea" maxlength="500" show-word-limit v-model="form.description"></el-input>
+            </el-form-item>
+            <el-form-item label="是否启用:">
+              <el-radio-group v-model="form.state">
+                <el-radio :label="0">是</el-radio>
+                <el-radio :label="1">否</el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item></el-form-item>
+          </el-form>
+        </div>
+        <div class="form-con" >
+          <el-tabs v-model="activeName" type="card" @tab-click="handleClick">
+            <el-tab-pane label="菜单权限" name="first">
+              <div class="menu" v-for="(item,index) in menu" :key="index">
+                  <div><el-checkbox :disabled="$route.params.type === 2" @change="handleItem(item)" v-model="item.authority">{{item.name}}</el-checkbox></div>
+                  <ul>
+                    <li v-for="(sub,idx) in item.children" :key="idx">
+                      <el-checkbox :disabled="$route.params.type === 2" @change="handleItem(sub)" class="s-el" v-model="sub.authority">{{sub.name}}</el-checkbox>
+                      <div class="verline"></div>
+                      <ul>
+                        <li v-for="(son,i) in sub.children" :key="i">
+                          <el-checkbox :disabled="$route.params.type === 2" @change="handleItem(son)" v-model="son.authority">{{son.name}}</el-checkbox></li>
+                      </ul>
+                    </li>
+                  </ul>
+              </div>
+            </el-tab-pane>
+            <el-tab-pane label="用户列表" name="second">
+              <el-table :data="tableData" style="width: 100%">
+                <el-table-column
+                  v-for="(item, idx) in data"
+                  :key="idx"
+                  :prop="item.prop"
+                  :label="item.label"
+                >
+                  <template slot-scope="scope">
+                    <img
+                      style="width:80px;border-radius:50%;"
+                      v-if="item.prop === 'head'"
+                      :src="scope.row[item.prop]"
+                      alt
+                    />
+                    <span v-else>{{scope.row[item.prop]}}</span>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </el-tab-pane>
+          </el-tabs>
+        </div>
+        <el-button :disabled="$route.params.type === 2" type="primary" @click="save">发布</el-button>
+        <el-button @click="$router.back()">取消</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+import SearchBar from '@/components/search-bar'
+import { VueEditor } from 'vue2-editor'
+
+function getIds (data) {
+  let arr = []
+  let fn = res => {
+    res && res.forEach(item => {
+      item.authority && arr.push(item.id)
+      item.children && fn(item.children)
+    })
+  }
+  fn(data)
+  return arr
+}
+
+let zt = {
+  0: '启用',
+  1: '停用'
+}
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+    VueEditor,
+    SearchBar
+  },
+  data () {
+    let type = this.$route.params.type
+    const crumbData = [
+      {
+        name: '角色信息',
+        id: 0
+      },
+      {
+        name: type === 3 ? '查看角色' : (type === 1 ? '编辑角色' : '新增角色'),
+        id: 1
+      }
+    ]
+    let data = [
+      {
+        prop: 'id',
+        label: '序号'
+      },
+      {
+        prop: 'head',
+        label: '用户头像'
+      },
+      {
+        prop: 'userName',
+        label: '账号'
+      },
+      {
+        prop: 'phone',
+        label: '手机号'
+      },
+      {
+        prop: 'qiyong',
+        label: '状态'
+      }
+    ]
+    return {
+      isIndeterminate: true,
+      crumbData,
+      type: this.$route.params.type,
+      id: this.$route.params.id,
+      activeName: 'first',
+      content: '<h1>Some initial content</h1>',
+      data,
+      tableData: [],
+      form: {
+        createTime: '',
+        description: '',
+        id: '',
+        roleKey: '',
+        roleName: '',
+        state: 0
+      },
+      menu: [],
+      rules: {
+        name: [{ required: true, message: '请选择部件名称', trigger: 'blur' }],
+        typeId: [
+          { required: true, message: '请选择部件类别', trigger: 'change' }
+        ],
+        block: [
+          { required: true, message: '请选择所属楼体', trigger: 'change' }
+        ],
+        zone: [{ required: true, message: '请选择部件位置', trigger: 'blur' }],
+        thumb: [{ required: true, message: '请选择展示封面', trigger: 'blur' }]
+      }
+    }
+  },
+  methods: {
+    handleClick (e) {
+      if (this.activeName === 'second') {
+        this.getTableData()
+      }
+    },
+    async getTableData () {
+      let result = await this.$http({
+        method: 'post',
+        headers: {
+          token: window.localStorage.getItem('token')
+        },
+        url: `/role/findUserListByRoleId`,
+        data: {
+          id: this.id
+        }
+      })
+
+      this.tableData = result.data
+      this.tableData.forEach((item, i) => {
+        item['qiyong'] = zt[item['state']]
+        item['idx'] = i + 1
+      })
+    },
+    handleItem (item) {
+      let {authority, parentId} = item
+      let fn = data => {
+        data.children && data.children.forEach(sub => {
+          sub.authority = authority
+          fn(sub)
+        })
+      }
+      fn(item)
+
+      let fnx = (parent = '', sub, parentId) => {
+        if (sub.id === parentId) {
+          if (sub.children) {
+            let isCheck = false
+            sub.children.forEach(it => {
+              if (it.authority) {
+                isCheck = it.authority
+                return false
+              }
+            })
+            sub.authority = isCheck
+          }
+          parent && fnx('', parent, sub.parentId)
+        } else {
+          sub.children && sub.children.forEach(it => {
+            fnx(sub, it, parentId)
+          })
+        }
+      }
+      this.menu && this.menu.forEach(sub => {
+        fnx('', sub, parentId)
+      })
+    },
+    save () {
+      this.$refs['roleform'].validate(async (valid) => {
+        if (valid) {
+          let {
+            id = '',
+            createTime,
+            description,
+            state,
+            roleKey,
+            roleName
+          } = this.form
+          let resources = getIds(this.menu)
+          let params = {
+            id,
+            createTime,
+            description,
+            roleKey,
+            state,
+            roleName,
+            resources
+          }
+
+          let result = await this.$http({
+            method: 'post',
+            data: params,
+            url: `/role/save`
+          })
+
+          if (result.code === 0) {
+            this.$alert('保存成功', '提示', {
+              confirmButtonText: '确定',
+              callback: () => {
+                this.$router.back()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: result.msg
+            })
+          }
+        }
+      })
+    },
+    async getMeun () {
+      let result = await this.$http({
+        method: 'post',
+        url: `/resource/find`,
+        data: {
+          id: this.id
+        }
+      })
+
+      this.menu = result.data
+    },
+    async getDetail () {
+      let result = await this.$http({
+        method: 'post',
+        headers: {
+          token: window.localStorage.getItem('token')
+        },
+        url: `/role/findRoleById`,
+        data: {
+          id: this.id
+        }
+      })
+
+      this.form = result.data
+      this.menu = result.data.resources
+    }
+  },
+
+  mounted () {
+    if (this.id && this.id !== 'none') {
+      this.getDetail()
+    } else {
+      this.getMeun()
+    }
+  }
+}
+</script>
+
+<style lang='less' scoped>
+/* 引入公共css类 */
+@import './style.less';
+
+</style>
+
+<style>
+.ql-picker-label {
+  line-height: 1;
+  overflow: hidden;
+}
+
+.avatar-uploader .el-upload {
+  /* border: 1px dashed #000; */
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+</style>

+ 84 - 0
src/pages/editPages/role/style.less

@@ -0,0 +1,84 @@
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+}
+
+.top-body .top-title{
+  font-weight: bold;
+  font-size: 16px;
+  margin-bottom: 20px;
+}
+
+.form-con{
+  width: 85%;
+  border: 1px solid #e5e5e5;
+  padding: 2% 10% 2% 2%;
+  margin-bottom: 20px;
+}
+
+
+.menu{
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  height: 140px;
+  margin-bottom: 10px;
+  >div{
+    flex: 1;
+    border: 1px solid #ccc;
+    border-radius: 4px;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    margin-right: 20px;
+    padding-left: 20px;
+  }
+  >ul{
+    border: 1px solid #ccc;
+    border-radius: 4px;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    flex-direction: column;
+    flex: 8;
+    >li{
+      padding: 0 20px;
+      width: 100%;
+      display: flex;
+      border-bottom: 1px solid #ccc;
+      flex: 1;
+      align-items: center;
+      &:last-of-type{
+        border: none;
+      }
+      .s-el{
+        width: 100px;
+      }
+      .verline{
+        width: 1px;
+        height: 100%;
+        background: #ccc;
+        margin-right: 20px;
+      }
+      >ul{
+        >li{
+          display: inline-block;
+          margin-right: 20px;
+        }
+      }
+    }
+  }
+}

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

@@ -0,0 +1,446 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData"></main-top>
+    <div class="table-interface">
+      <div class="top">
+        <div class="top-left">
+          <div class="tl-top">
+            <InfoCard  v-for="(item,i) in cardArr" :key="i" :data='item' class="i-card"/>
+          </div>
+          <div class="tl-bottom card">
+            <Nums v-for="(item, i) in nums" :key="i" :data='item' />
+          </div>
+        </div>
+        <div class="top-right card">
+          <p class="theme-color1">累计访问人数</p>
+          <div class="select">A馆万物墙10</div>
+          <div class="nlt">
+            <PowerBar class="n-i" v-for="(item,i) in nlt" :data='item' :key="i"/>
+          </div>
+        </div>
+      </div>
+
+      <div class="plate02">
+        <div class="p2-left">
+          <trend />
+        </div>
+        <div class="p2-right card">
+          <HotBang :data='hot'/>
+        </div>
+      </div>
+      <div class="plate04">
+        <div class="pl4-i card" v-for="(item,i) in tongji" :key="i">
+          <p class="p3-txt theme-color1">{{item.name}}</p>
+          <PieTu  :id="'pie'+i" :data="item"/>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+import SearchBar from '@/components/search-bar'
+import InfoCard from '@/components/info-card'
+import Nums from '@/components/nums'
+import PowerBar from '@/components/power-bar'
+import trend from '@/components/trend'
+import HotBang from '@/components/hot-bang'
+import FocusBang from '@/components/focus-bang'
+import PieTu from '@/components/pie-tu'
+
+const crumbData = [
+  {
+    name: '首页',
+    id: -1
+  }
+]
+
+const cardArr = [
+  {
+    name: '系统总体运行时间',
+    icon: 'iconsys',
+    sub1: [
+      {
+        bold: {
+          txt: '1236',
+          color: '#a09d50'
+        },
+        txt: '天'
+      }
+    ],
+    sub2: [
+      {
+        bold: {
+          txt: '18',
+          color: '#a09d50'
+        },
+        txt: '时'
+      }, {
+        bold: {
+          txt: '21',
+          color: '#a09d50'
+        },
+        txt: '分'
+      }, {
+        bold: {
+          txt: '53',
+          color: '#a09d50'
+        },
+        txt: '秒'
+      }
+    ]
+  },
+  {
+    name: '无人互动运行时间',
+    icon: 'iconsys1',
+    sub1: [
+      {
+        bold: {
+          txt: '8',
+          color: '#a09d50'
+        },
+        txt: '天'
+      }
+    ],
+    sub2: [
+      {
+        bold: {
+          txt: '07',
+          color: '#a09d50'
+        },
+        txt: '时'
+      }, {
+        bold: {
+          txt: '32',
+          color: '#a09d50'
+        },
+        txt: '分'
+      }, {
+        bold: {
+          txt: '36',
+          color: '#a09d50'
+        },
+        txt: '秒'
+      }
+    ]
+  },
+  {
+    name: '终端展示数',
+    icon: 'iconsys2',
+    sub1: [
+      {
+        bold: {
+          txt: '8',
+          color: '#a09d50'
+        },
+        txt: '已启用'
+      }
+    ],
+    sub2: [
+      {
+        bold: {
+          txt: '16',
+          color: '#a09d50'
+        },
+        txt: '总数'
+      }
+    ]
+  }
+]
+
+const nums = [
+  {
+    name: '展示总数',
+    sum: 5
+  },
+  {
+    name: '文物总数',
+    sum: 2634
+  },
+  {
+    name: '本月新增文物',
+    sum: 36
+  },
+  {
+    name: '文物下载量',
+    sum: 162685
+  },
+  {
+    name: '累计点赞数',
+    sum: 625658
+  }
+]
+
+const nlt = [
+  {
+    num: 365845,
+    content: 25,
+    color: '#67c241',
+    bottomname: '青铜'
+  },
+  {
+    num: 245854,
+    content: 20,
+    color: '#e6a139',
+    bottomname: '瓷器'
+  },
+  {
+    num: 175458,
+    content: 15,
+    color: '#f76b6c',
+    bottomname: '陶器'
+  }
+]
+
+const hot = [
+  {
+    name: '西周克盉',
+    num: 95684
+  },
+  {
+    name: '青白玉“绵绵瓜瓞”御制诗洗',
+    num: 85685
+  },
+  {
+    name: '吃古柯叶的厄瓜多尔祭司',
+    num: 95342
+  },
+  {
+    name: '宋代定窑白釉童子诵经壶',
+    num: 95681
+  },
+  {
+    name: '西周伯矩鬲',
+    num: 75684
+  },
+  {
+    name: '雍正珊瑚红地珐琅彩花鸟纹瓶',
+    num: 95685
+  },
+  {
+    name: '西周克罍',
+    num: 95124
+  },
+  {
+    name: '元代白玉凌霄花饰件',
+    num: 93483
+  },
+  {
+    name: '北魏“大代”款铜鎏金释迦牟...',
+    num: 99684
+  },
+  {
+    name: '秘鲁莫切人物陶罐',
+    num: 85686
+  }
+]
+
+const focus = [
+  {
+    num: 1,
+    zan: 368,
+    sub1: '清 陶器',
+    sub2: '国家一级文物',
+    name: '青白玉“绵绵瓜瓞”御制诗洗',
+    img: 'http://show.4dage.com/3D/2018/model/SD/images/s10.jpg'
+  },
+  {
+    num: 2,
+    zan: 297,
+    sub1: '唐 陶器',
+    sub2: '国家一级文物',
+    name: '秘鲁莫切人物陶罐',
+    img: 'http://model3d.4dage.com/3D/2018/model/DG/images/ger01.jpg'
+
+  },
+  {
+    num: 3,
+    zan: 242,
+    sub1: '唐 陶器',
+    sub2: '国家一级文物',
+    name: '西周克盉',
+    img: 'http://show.4dage.com/3D/2018/model/SD/images/s08.jpg'
+  }
+]
+
+const reci = [
+  {
+    name: '陶瓷',
+    hot: '+8'
+  }, {
+    name: '青铜器',
+    hot: '+6'
+  }, {
+    name: '玉器',
+    hot: '+5'
+  }, {
+    name: '书画',
+    hot: '+3'
+  }, {
+    name: '西周',
+    hot: '+2'
+  }
+]
+
+const shangsheng = [
+  {
+    name: '青白玉“绵绵瓜瓞”御制诗洗',
+    hot: '+8',
+    img: 'http://show.4dage.com/3D/2018/model/SD/images/s10.jpg'
+  }, {
+    name: '秘鲁莫切人物陶罐',
+    hot: '+6',
+    img: 'http://model3d.4dage.com/3D/2018/model/DG/images/ger01.jpg'
+  }, {
+    name: '西周克罍',
+    hot: '+5',
+    img: 'http://show.4dage.com/3D/2018/model/SD/images/s08.jpg'
+  }, {
+    name: '北魏“大代”款铜鎏金释迦牟尼佛坐像',
+    hot: '+3',
+    img: 'http://show.4dage.com/3D/2018/model/SD/images/s05.jpg'
+  }, {
+    name: '元青花凤首扁壶',
+    hot: '+2',
+    img: 'http://show.4dage.com/3D/2018/model/SD/images/s03.jpg'
+  }
+]
+
+const xiajiang = [
+  {
+    name: '青白玉“绵绵瓜瓞”御制诗洗',
+    hot: '-8',
+    img: 'http://show.4dage.com/3D/2018/model/SD/images/s10.jpg'
+  }, {
+    name: '秘鲁莫切人物陶罐',
+    hot: '-6',
+    img: 'http://model3d.4dage.com/3D/2018/model/DG/images/ger01.jpg'
+  }, {
+    name: '西周克罍',
+    hot: '-5',
+    img: 'http://show.4dage.com/3D/2018/model/SD/images/s08.jpg'
+  }, {
+    name: '北魏“大代”款铜鎏金释迦牟尼佛坐像',
+    hot: '-3',
+    img: 'http://show.4dage.com/3D/2018/model/SD/images/s05.jpg'
+  }, {
+    name: '元青花凤首扁壶',
+    hot: '-2',
+    img: 'http://show.4dage.com/3D/2018/model/SD/images/s03.jpg'
+  }
+]
+
+const wwlb = {
+  name: 'Top100文物占比',
+  header: ['青铜', '瓷器', '陶器'],
+  data: [
+    {value: 335, name: '青铜'},
+    {value: 310, name: '瓷器'},
+    {value: 734, name: '陶器'}
+  ],
+  color: ['#67c241', '#e6a139', '#f76b6c']
+}
+
+const tongji = [
+  {
+    name: '文物类别统计',
+    header: ['青铜', '瓷器', '陶器'],
+    center: ['65%', '60%'],
+    data: [
+      {value: 335, name: '青铜'},
+      {value: 310, name: '瓷器'},
+      {value: 734, name: '陶器'}
+    ],
+    color: ['#67c241', '#e6a139', '#f76b6c']
+  },
+  {
+    name: '文物品级统计',
+    center: ['65%', '60%'],
+    header: ['国家一级文物', '国家二级文物', '国家三级文物', '一般文物'],
+    data: [
+      {value: 335, name: '国家一级文物'},
+      {value: 310, name: '国家二级文物'},
+      {value: 734, name: '国家三级文物'},
+      {value: 40, name: '一般文物'}
+
+    ],
+    color: ['#62AF3E', '#4DD0EC', '#E6A23C', '#EE7818']
+  },
+  {
+    name: '各分馆人流访问量',
+    center: ['65%', '60%'],
+    header: ['展馆A', '展馆B', '展馆C', '展馆D', '展馆E', '展馆F'],
+    data: [
+      {value: 335, name: '展馆A'},
+      {value: 210, name: '展馆B'},
+      {value: 350, name: '展馆C'},
+      {value: 410, name: '展馆D'},
+      {value: 510, name: '展馆E'},
+      {value: 810, name: '展馆F'}
+    ],
+    color: ['#62AF3E', '#4DD0EC', '#E6A23C', '#EE7818', '#F56C6C', '#3B87ED']
+  },
+  {
+    name: '展览/维修文物统计',
+    center: ['65%', '60%'],
+    header: ['展览中', '维修中'],
+    data: [
+      {value: 735, name: '展览中'},
+      {value: 134, name: '维修中'}
+    ],
+    color: ['#A7A15F', '#E6A23C']
+  }
+]
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+    SearchBar,
+    InfoCard,
+    Nums,
+    PowerBar,
+    trend,
+    HotBang,
+    FocusBang,
+    PieTu
+  },
+  data () {
+    return {
+      crumbData,
+      nlt,
+      cardArr,
+      nums,
+      hot,
+      reci,
+      xiajiang,
+      focus,
+      shangsheng,
+      wwlb,
+      tongji
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {},
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {},
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+
+  }
+}
+</script>
+
+<style scoped>
+/* 引入公共css类 */
+@import url(./style);
+</style>

+ 185 - 0
src/pages/home/style.css

@@ -0,0 +1,185 @@
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 4rem);
+}
+
+.top-body .top-con{
+  font-weight: bold;
+}
+
+.top{
+  display: flex;
+  justify-content: space-between;
+  align-items: stretch;
+  width: 100%;
+  height: 400px;
+  margin: 1rem 0;
+}
+.top-left{
+  width: calc(100% - 390px - 1rem);
+  margin-right: 1rem;
+  position: relative;
+}
+
+.tl-top{
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  height: 180px;
+}
+
+.tl-bottom{
+  height: calc(400px - 1rem - 180px);
+  width: 100%;
+  position: absolute;
+  bottom: 0;
+  padding: 1.5em;
+  box-sizing: border-box;;
+  display: flex;
+  justify-content: space-around;
+}
+.i-card{
+  width: calc((100% - 2rem) / 3);
+}
+
+.top-right{
+  color: #fff;
+  width: 390px;
+  flex: auto;
+  flex-shrink: 0;
+  height: 100%;
+  padding: 1.5em;
+}
+.nlt{
+  display: flex;
+  justify-content: space-between;
+  width: 100%;
+  margin-top: 40px;
+}
+.n-i{
+  width: 30%;
+}
+
+.top-right p:first-of-type{
+  font-weight: bold;
+}
+
+.top-right .select{
+  float: right;
+}
+
+.plate02{
+  display: flex;
+  justify-content: space-between;
+  align-items: stretch;
+  width: 100%;
+  height: 400px;
+  margin: 1rem 0;
+}
+
+.plate02 .p2-left{
+  width: calc(100% - 390px - 1rem);
+  margin-right: 1rem;
+  position: relative;
+}
+
+.plate02 .p2-right{
+  color: #fff;
+  width: 390px;
+  flex: auto;
+  flex-shrink: 0;
+  height: 100%;
+}
+
+.plate03{
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  height: 550px;
+  margin: 1rem 0;
+}
+
+.pla3{
+  display: flex;
+  width: 100%;
+  justify-content: space-between;
+  padding: 1.5rem;
+}
+
+.p3-left{
+  width: 32%!important;
+  height: 220px;
+}
+
+.p3-right{
+  width: calc(100% - 32% - 2%);
+  display: flex;
+  justify-content: space-between;
+}
+
+.pr-l,.pr-c,.pr-r{
+  width: 31%;
+}
+
+.v-line{
+  width: 1px;
+  height: 100%;
+  background: rgba(255, 255, 255, 0.05);
+  margin: 0 10px;
+}
+
+.p3-right ul{
+  width: 100%;
+}
+
+.p3-right ul li{
+  justify-content: space-between;
+  display: flex;
+  width: 100%;
+  margin: 25px 0;
+  font-size: 14px;
+}
+
+.p3-right p{
+  font-weight: bold;
+}
+
+.p3-right ul li img{
+  width: 28px;
+  vertical-align: middle;
+  border-radius: 3px;
+}
+
+
+.p3-txt{
+  font-weight: bold;
+}
+
+#wwlb{
+  width: 100%;
+  height: 200px;
+}
+
+.plate04{
+  display: flex;
+  justify-content: space-between;
+  width: 100%;
+  height: 300px;
+  margin: 1rem 0;
+}
+
+.pl4-i{
+  width: 24%;
+  width: calc((100% - 3rem) / 4);
+  padding: 1.5rem;
+}

+ 255 - 0
src/pages/information/index.vue

@@ -0,0 +1,255 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData"></main-top>
+    <div class="table-interface card">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span>按资讯类型查看:</span>
+            <el-select style="width:120px;" v-model="region" placeholder="请选择">
+              <el-option label="全部" value=""></el-option>
+              <el-option label="海报轮播" :value="0"></el-option>
+              <el-option label="视频轮播" :value="1"></el-option>
+            </el-select>
+            <span style="margin-left:20px;">资讯名称:</span>
+            <el-input style="width:220px;margin-right:20px;" v-model="inputKey" placeholder="请输入资讯名称"></el-input>
+            <el-button type="primary" @click="getInformation">查找</el-button>
+            <el-button @click="inputKey=''">重置</el-button>
+          </div>
+          <div class="info-right">
+            <el-button type="primary" @click="$router.push({name:'edit-information',params:{type:0}})">发布资讯</el-button>
+          </div>
+        </div>
+        <el-table :data="tableData" style="width: 100%">
+          <el-table-column
+            v-for="(item, idx) in data"
+            :key="idx"
+            :prop="item.prop"
+            :label="item.label"
+          >
+          <template slot-scope="scope">
+            <img style="width:80px" v-if="item.prop === 'contentUrl'" :src="scope.row[item.prop]" alt="">
+            <span v-else>{{scope.row[item.prop]}}</span>
+          </template>
+          </el-table-column>
+          <el-table-column label="状态">
+            <template slot-scope="scope" v-if="scope.row.qiyong">
+              <el-switch
+                @change='changeState(scope.row)'
+                v-model="scope.row.qiyong.st"
+              >
+              </el-switch>
+              <span >{{scope.row.qiyong.text}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span class="o-span" @click="goto(scope.row)">编辑</span>
+              <span class="o-span" @click="del(scope.row)">删除</span>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination @current-change="handleCurrentChange" :current-page.sync="currentPage" :page-size="size" layout="prev, pager, next, jumper" :total="total">
+          </el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+import SearchBar from '@/components/search-bar'
+const crumbData = [
+  {
+    name: '资讯管理',
+    id: 2
+  }
+]
+let zxlx = {
+  0: '海报轮播',
+  1: '视频轮播'
+}
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+    SearchBar
+  },
+  data () {
+    let data = [
+      {
+        prop: 'orderNum',
+        label: '展示顺序'
+      },
+      {
+        prop: 'leixing',
+        label: '资讯类型'
+      },
+      {
+        prop: 'contentUrl',
+        label: '缩略图'
+      },
+      {
+        prop: 'name',
+        label: '资讯名称'
+      },
+      {
+        prop: 'date',
+        label: '轮播时间'
+      }
+    ]
+
+    return {
+      crumbData,
+      data,
+      region: '',
+      inputKey: '',
+      currentPage: 1,
+      size: 10,
+      total: 0,
+      tableData: []
+    }
+  },
+  watch: {
+    region () {
+      this.refresh()
+    },
+    currentPage () {
+      this.refresh()
+    },
+    size () {
+      this.refresh()
+    },
+    inputKey () {
+      this.refresh()
+    }
+  },
+  mounted () {
+    this.refresh()
+  },
+  methods: {
+    goto (item) {
+      window.localStorage.setItem('editInfo', JSON.stringify(item))
+      this.$router.push({name: 'edit-information', params: {type: 1}})
+      this.$bus.$emit('editinfo', item)
+    },
+    async changeState (item) {
+      console.log(item)
+      // let { name, id, typeId, equipmentId, description } = item
+      // let data = { name, typeId, equipmentId, state: !item.qiyong.st ? 1 : 0, description, id }
+      let {type, id, name, contentUrl, orderNum, startTime, endTime, description} = item
+      let data = {name, id, type: Number(type), contentUrl, orderNum, state: !item.qiyong.st ? 1 : 0, startTime, endTime, description}
+      this.$http.post('/information/updateInformation', data).then(res => {
+        if (res.code === 0) {
+          this.refresh()
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    refresh () {
+      this.loading = true
+      this.getInformation()
+      this.loading = false
+    },
+    handleCurrentChange (val) {
+      this.currentPage = val
+    },
+    fixState (state) {
+      let obj = {}
+      switch (Number(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
+    },
+    del (item) {
+      let data = {
+        id: item.id
+      }
+      this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http.post('/information/deleteInformation', data).then(res => {
+          if (res.code === 0) {
+            this.$alert('删除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.msg
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    async getInformation () {
+      let params = {
+        type: this.region,
+        name: this.inputKey,
+        pageNum: this.currentPage,
+        pageSize: this.size
+      }
+      let result = await this.$http({
+        method: 'post',
+        data: params,
+        url: '/information/list'
+      })
+
+      if (result.code !== 0) {
+        return
+      }
+      this.tableData = result.data.list
+      this.total = result.data.total
+      this.tableData.forEach(item => {
+        item['date'] = this.$base.timestampToTime(item['startTime']) + '至' + this.$base.timestampToTime(item['endTime'])
+        item['leixing'] = zxlx[item['type']]
+        item['qiyong'] = this.fixState(item['state'])
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+/* 引入公共css类 */
+@import url(./style);
+</style>

+ 111 - 0
src/pages/information/style.css

@@ -0,0 +1,111 @@
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.top-body .top-con{
+  font-weight: bold;
+}
+.table-title{
+  padding: 1rem 1rem 1rem 0 ;
+  font-size: 1rem;
+  color: #2d2d2d;
+  border-bottom: 1px solid #ccc;
+  display: flex;
+  justify-content: space-between;
+}
+
+.more{
+  color: #ec652d;
+  cursor: pointer;
+}
+
+.top-right{
+  background-color: #ec652d;
+  height: 3.5625rem;
+  line-height: 3.5625rem;
+  color: #fff;
+  padding: 0 1.875rem;
+  border-radius: .3125rem;
+  font-size: 1.125rem;
+  font-weight: bold;
+}
+
+.search-body{
+  background-color: #fff;
+  margin: 1.25rem 0;
+}
+
+.interface-table{
+  height: calc(100% - 17.1875rem);
+  overflow-x: hidden;
+  background-color: #fff;
+  padding: 0 1.125rem 2.375rem;
+  box-sizing: border-box;
+}
+
+.zan-con{
+  display: flex;
+  width: 100%;
+  justify-content: space-around;
+  margin-top: 1.5rem;
+  text-align: center;
+  font-size: 1.125rem;
+}
+
+.zan-con .line{
+  height: 8rem;
+  width: 1px;
+  background: #ccc;
+}
+
+.zan-con .zan-contain{
+  display: flex;
+  justify-content: space-between;
+  flex-direction: column;
+}
+
+.zan-con .zan-contain p{
+  font-size: 2.25rem;
+}
+
+.zan-con .zan-contain p:first-child{
+  font-size: .875rem;
+  line-height: 1.5;
+}
+
+.zan-sub{
+  text-align: right;
+  margin-top: 1.25rem;
+  color: #a5a5a5;
+  font-size: .875rem;
+}
+
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+}
+
+
+.info-top{
+  padding: 20px 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px #a5a5a5 solid;
+}
+
+.o-span{
+  cursor: pointer;
+  color: rgb(7, 152, 244);
+}
+.e-pagination{
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 1.5625rem;
+}

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

@@ -0,0 +1,136 @@
+<!--  -->
+<template>
+<div class="aside">
+  <div class="aside-list">
+    <div class="aside-item">
+      <div :class="{active:activeIdx === -1}" @click="go(-1,'/')"><img :src="require('@/assets/img/01jk.png')" >首页</div>
+      <!-- <div @click="go(0,'/message')" :class="{active:activeIdx === 0}">消息管理</div> -->
+      <div @click="go(1,'/user-analysis')" :class="{active:activeIdx === 1}">数据统计</div>
+    </div>
+    <div class="aside-item">
+      <div><img :src="require('@/assets/img/02fb.png')">工作管理</div>
+      <!-- <div @click="go(2,'/information')" :class="{active:activeIdx === 2}">资讯管理</div> -->
+      <div @click="go(3,'/display')" :class="{active:activeIdx === 3}">展示管理</div>
+      <div @click="go(4,'/cultural-relic')" :class="{active:activeIdx === 4}">文物库</div>
+      <!-- <div @click="go(5,'/questionnaire')" :class="{active:activeIdx === 5}">问卷管理</div> -->
+
+    </div>
+    <div class="aside-item" >
+      <div><img :src="require('@/assets/img/03mg.png')">系统管理</div>
+      <div @click="go(6,'/user')" :class="{active:activeIdx === 6}">用户管理</div>
+      <div @click="go(7,'/work-log')" :class="{active:activeIdx === 7}">工作日志</div>
+      <div @click="go(8,'/modify')" :class="{active:activeIdx === 8}">密码修改</div>
+    </div>
+    <div class="aside-item" >
+      <div><img :src="require('@/assets/img/04fb.png')">高级管理</div>
+      <div @click="go(9,'/role')" :class="{active:activeIdx === 9}">角色管理</div>
+      <div @click="go(10,'/device')" :class="{active:activeIdx === 10}">设备管理</div>
+    </div>
+  </div>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {},
+  data () {
+    // 这里存放数据
+    return {
+      // activeIdx: 0
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {
+    activeIdx: {
+      get: function () {
+        return this.$route.meta.index
+      },
+      set: function () {
+      }
+    }
+  },
+  // 监控data中的数据变化
+  watch: {
+
+  },
+  // 方法集合
+  methods: {
+    go (id, url) {
+      this.activeIdx = this.$route.meta.index
+      this.$router.push(url)
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+
+  }
+
+}
+</script>
+
+<style scoped>
+.aside-list{
+  width: 100%;
+
+}
+.aside-item {
+  padding: .625rem 0;
+}
+.aside-item:last-child{
+  border-bottom:none;
+}
+
+.aside-item div{
+  height: 2.75rem;
+  line-height: 2.75rem;
+  margin: .0625rem auto;
+  width: 80%;
+  padding-left: 3.4375rem;
+  cursor: pointer;
+  color: rgba(0, 0, 0, 1);
+}
+.aside-item div:not(:first-child):hover{
+  background-color: #6c1c1c;
+  border-radius: 80px;
+  color: #fff;
+}
+
+.aside-item div:first-child{
+  padding-left: 1.8125rem;
+  display: flex;
+  align-items: center;
+  color: #888888;
+  font-size: .75rem;
+}
+
+.aside-item div:first-child img{
+  width: 1.1rem;
+  height: 1.1rem;
+  margin-right: .625rem;
+}
+
+.aside-item .active{
+  background-color: #6c1c1c;
+  border-radius: 80px;
+  position: relative;
+  color: #fff!important;
+}
+.aside-item .active::after{
+  content: '';
+  width: 40px;
+  min-height: 40px;
+  right: 0px;
+  top: 50%;
+  transform: translateY(-50%);
+  position: absolute;
+  background:url('~@/assets/img/icon2s.png') no-repeat center center!important;
+}
+</style>

+ 47 - 0
src/pages/layout/footer.vue

@@ -0,0 +1,47 @@
+<!--  -->
+<template>
+<div class=''></div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+export default {
+// import引入的组件需要注入到对象中才能使用
+  components: {},
+  data () {
+    // 这里存放数据
+    return {
+
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+<style scoped>
+/* 引入公共css类 */
+
+</style>

+ 130 - 0
src/pages/layout/head.vue

@@ -0,0 +1,130 @@
+<!--  -->
+<template>
+<div class='header'>
+  <div class="header-title">
+    <img src="@/assets/img/4dage-logo.png" alt="">
+    <!-- <span>大屏后台管理系统</span> -->
+  </div>
+  <div class="header-user">
+    <div class="avatar">
+      <img :src="head" alt="">
+      <span>高级管理员</span>
+    </div>
+    <div  @click="logout" class="logout"><img src="@/assets/img/logout.png" alt="">退出</div>
+  </div>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {},
+  data () {
+    return {
+      head: ''
+    }
+  },
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+    logout () {
+      window.localStorage.setItem('userInfo', '')
+      window.localStorage.setItem('token', '')
+      this.$router.push({name: 'login'})
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+    let userInfo = window.localStorage.getItem('userInfo') || ''
+    let tmp = ''
+    if (userInfo) {
+      tmp = JSON.parse(userInfo)
+    }
+
+    if (tmp) {
+      this.head = userInfo.head
+    }
+    // this.updateInfo()
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+
+<style scoped>
+.header {
+  height: 4.25rem;
+  width: 100%;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  line-height: 4.25rem;
+  padding: 0 1.875rem;
+  box-sizing: border-box;
+  color: #fff;
+  background: url('~@/assets/img/bar.png') no-repeat center center;
+}
+
+.header-title {
+  color: #b9b47f;
+  font-size: 1.25rem;
+  text-align: center;
+  vertical-align: middle;
+}
+.header-title img{
+  vertical-align: middle;
+  height: 50px;
+  margin-right: 30px;
+}
+.header-title span{
+  vertical-align: middle;
+  display: inline-block;
+}
+.header-user {
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+}
+
+.header-user .logout img {
+  width: 20px;
+  height: 20px;
+  margin: 0 10px 0 30px;
+}
+
+.header-user .logout {
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+}
+
+.header-user .avatar{
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+  height: 3rem;
+}
+
+.header-user .avatar span{
+  margin-left: 10px;
+}
+
+.header-user .avatar img{
+  width:3rem;
+  height:3rem;
+  border-radius:50%;
+}
+</style>

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

@@ -0,0 +1,55 @@
+<template>
+<div class="body theme" >
+  <Head />
+  <div class="aside-con card">
+    <Aside />
+  </div>
+    <router-view class="main-view" />
+  <Footer />
+</div>
+</template>
+
+<script>
+import Head from './head'
+import Footer from './footer'
+import Aside from './Aside'
+
+export default {
+  components: {
+    Head,
+    Aside,
+    Footer
+  },
+  computed: {
+    userId () {
+      return window.localStorage.getItem('userInfo')
+    }
+  },
+  mounted () {
+    if (!this.userId) {
+      // this.$router.push('/login')
+    }
+  }
+}
+</script>
+
+<style scoped>
+.body{
+  width: 100%;
+  height: 100%;
+}
+.aside-con {
+  width: 15rem;
+  position: fixed;
+  height: calc(100% - 8rem);
+  margin: 1.875rem 1.25rem 1.875rem 1.875rem;
+  border-radius: .625rem;
+  overflow: hidden;
+}
+.main-view{
+  margin: 1.875rem 1.875rem 0 18.25rem;
+  width: calc(100% - 20.125rem);
+  height: calc(100% - 8rem);
+  overflow: hidden;
+}
+</style>

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

@@ -0,0 +1,119 @@
+<!--  -->
+<template>
+<div class='layout'>
+  <div class="layout-con">
+    <img class="logo" :src="require('@/assets/img/4dage-logo.png')" alt="">
+    <img class="lay-bg" :src="require('@/assets/img/bg.png')" alt="">
+    <div class="middle">
+      <div class="middle-con">
+        <div class="middle-title">
+        <div>后台管理系统</div>
+        <div class="middle-subtitle">欢迎登录</div>
+      </div>
+      <el-form :rules="ruleLogin" status-icon :model="formLogin" ref="formLogin">
+        <el-form-item prop="username">
+          <el-input v-model="formLogin.username" placeholder="账号名"></el-input>
+        </el-form-item>
+        <el-form-item prop="password">
+          <el-input @keyup.enter.native="submitForm('formLogin')" v-model="formLogin.password" placeholder="账号密码" type="password"></el-input>
+        </el-form-item>
+        <el-form-item>
+          <div class="login" @click="submitForm('formLogin')">登录</div>
+        </el-form-item>
+      </el-form>
+      </div>
+    </div>
+  </div>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {},
+  data () {
+    var checkUsername = (rule, value, callback) => {
+      if (!value) {
+        return callback(new Error('用户名不能为空'))
+      }
+      setTimeout(() => {
+        if (value.length > 10) {
+          callback(new Error('用户名字符不能大于10位'))
+        } else {
+          callback()
+        }
+      }, 1000)
+    }
+    var validatePass = (rule, value, callback) => {
+      if (value === '') {
+        callback(new Error('请输入密码'))
+      } else {
+        callback()
+      }
+    }
+    // 这里存放数据
+    return {
+      formLogin: {
+        username: '',
+        password: '',
+        region: 'high'
+      },
+      ruleLogin: {
+        username: [
+          { validator: checkUsername, trigger: 'blur' }
+        ],
+        password: [
+          { validator: validatePass, trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+    submitForm (formName) {
+      this.$refs[formName].validate((valid) => {
+        let data = {
+          userName: this.formLogin.username,
+          password: this.formLogin.password
+        }
+        if (valid) {
+          this.$http.post('/login', data).then(res => {
+            if (res.code === 0) {
+              window.localStorage.setItem('userInfo', JSON.stringify(res.data))
+              window.localStorage.setItem('token', res.data.token)
+              this.$router.push('/')
+            } else {
+              this.$notify.error({
+                title: '错误',
+                message: res.msg
+              })
+            }
+          })
+        } else {
+          return false
+        }
+      })
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+
+  }
+}
+</script>
+
+<style scoped>
+/* 引入公共css类 */
+@import url(./style);
+</style>

+ 63 - 0
src/pages/login/style.css

@@ -0,0 +1,63 @@
+.el-button--primary {
+  width: 100%;
+}
+.layout-con{
+  background-color: #6D1C1C;
+}
+.logo{
+  position: fixed;
+  top: 20px;
+  left: 40px;
+  min-width: 170px;
+  height: auto;
+}
+
+.lay-bg{
+  width: 100%;
+  position: fixed;
+  transform: translate(-50%,-50%);
+  top: 50%;
+  left: 50%;
+  z-index: -1;
+}
+.middle{
+  background:url('~@/assets/img/bg2.png') no-repeat;
+  background-size: cover;
+  width: 36.75rem;
+  top: 50vh;
+  left: 77vw;
+  height: auto;
+  padding: 4rem;
+  text-align: center;
+}
+.middle-subtitle{
+  background:url('~@/assets/img/icon.png') no-repeat center center;
+  font-size: 18px;
+  font-weight: bold;
+  margin-top: 1.2rem;
+}
+.middle-title{
+  margin-bottom: 2rem;
+  color: #741A1A;
+  font-size: 28px;
+  line-height: 45px;
+  font-weight: bold;
+}
+.middle-con{
+  width: 70%;
+  margin: 0 auto;
+}
+
+.middle-bg{
+
+}
+
+.login{
+  width: 100%;
+  color: #741A1A;
+  background: #DDCC92;
+  cursor: pointer;
+  border-radius: 4px;
+  font-weight: bold;
+  font-size: 18px;
+}

+ 89 - 0
src/pages/message/index.vue

@@ -0,0 +1,89 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData"></main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <el-table :data="tableData" style="width: 100%">
+          <el-table-column
+            v-for="(item, idx) in data"
+            :key="idx"
+            :prop="item.prop"
+            :label="item.label"
+          ></el-table-column>
+          <el-table-column label="操作">
+            <template>
+              <span class="o-span">标为已读</span>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+import SearchBar from '@/components/search-bar'
+const crumbData = [
+  {
+    name: '消息管理',
+    id: 0
+  }
+]
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+    SearchBar
+  },
+  data () {
+    // 这里存放数据
+    let data = [
+      {
+        prop: 'id',
+        label: '序号'
+      },
+      {
+        prop: 'type',
+        label: '类型'
+      },
+      {
+        prop: 'content',
+        label: '内容'
+      },
+      {
+        prop: 'date',
+        label: '时间'
+      }
+
+    ]
+
+    return {
+      crumbData,
+      data,
+      tableData: []
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {},
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {},
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+  }
+}
+</script>
+
+<style scoped>
+/* 引入公共css类 */
+@import url(./style);
+</style>

+ 99 - 0
src/pages/message/style.css

@@ -0,0 +1,99 @@
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.top-body .top-con{
+  font-weight: bold;
+}
+.table-title{
+  padding: 1rem 1rem 1rem 0 ;
+  font-size: 1rem;
+  color: #2d2d2d;
+  border-bottom: 1px solid #ccc;
+  display: flex;
+  justify-content: space-between;
+}
+
+.more{
+  color: #ec652d;
+  cursor: pointer;
+}
+
+.top-right{
+  background-color: #ec652d;
+  height: 3.5625rem;
+  line-height: 3.5625rem;
+  color: #fff;
+  padding: 0 1.875rem;
+  border-radius: .3125rem;
+  font-size: 1.125rem;
+  font-weight: bold;
+}
+
+.search-body{
+  background-color: #fff;
+  margin: 1.25rem 0;
+}
+
+.interface-table{
+  height: calc(100% - 17.1875rem);
+  overflow-x: hidden;
+  background-color: #fff;
+  padding: 0 1.125rem 2.375rem;
+  box-sizing: border-box;
+}
+
+.zan-con{
+  display: flex;
+  width: 100%;
+  justify-content: space-around;
+  margin-top: 1.5rem;
+  text-align: center;
+  font-size: 1.125rem;
+}
+
+.zan-con .line{
+  height: 8rem;
+  width: 1px;
+  background: #ccc;
+}
+
+.zan-con .zan-contain{
+  display: flex;
+  justify-content: space-between;
+  flex-direction: column;
+}
+
+.zan-con .zan-contain p{
+  font-size: 2.25rem;
+}
+
+.zan-con .zan-contain p:first-child{
+  font-size: .875rem;
+  line-height: 1.5;
+}
+
+.zan-sub{
+  text-align: right;
+  margin-top: 1.25rem;
+  color: #a5a5a5;
+  font-size: .875rem;
+}
+
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+}
+
+
+#tjfx{
+  width: 100%;
+  height: 400px;
+}

+ 0 - 0
src/pages/modify/index.vue


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.