瀏覽代碼

第一次提交

zhuxiuping 2 年之前
父節點
當前提交
4248110700
共有 66 個文件被更改,包括 45396 次插入0 次删除
  1. 43 0
      .babelrc
  2. 9 0
      .editorconfig
  3. 5 0
      .eslintignore
  4. 29 0
      .eslintrc.js
  5. 17 0
      .gitignore
  6. 10 0
      .postcssrc.js
  7. 41 0
      build/build.js
  8. 54 0
      build/check-versions.js
  9. 101 0
      build/utils.js
  10. 22 0
      build/vue-loader.conf.js
  11. 92 0
      build/webpack.base.conf.js
  12. 99 0
      build/webpack.dev.conf.js
  13. 149 0
      build/webpack.prod.conf.js
  14. 7 0
      config/dev.env.js
  15. 96 0
      config/index.js
  16. 4 0
      config/prod.env.js
  17. 7 0
      config/test.env.js
  18. 15 0
      index.html
  19. 38677 0
      package-lock.json
  20. 98 0
      package.json
  21. 83 0
      src/App.vue
  22. 二進制
      src/assets/logo.png
  23. 160 0
      src/components/consumption/index.vue
  24. 200 0
      src/components/earlyWarning/index.vue
  25. 797 0
      src/components/eventPlanning/index.vue
  26. 291 0
      src/components/form/index.vue
  27. 191 0
      src/components/index/index.css
  28. 191 0
      src/components/index/index.vue
  29. 91 0
      src/components/login/login.css
  30. 169 0
      src/components/login/login.vue
  31. 648 0
      src/components/newsFocus/index.vue
  32. 556 0
      src/components/peopleCoefficient/index.vue
  33. 845 0
      src/components/serve/index.vue
  34. 238 0
      src/components/zhuanghaoguanli/zhuanghaoguanli.css
  35. 653 0
      src/components/zhuanghaoguanli/zhuanghaoguanli.vue
  36. 54 0
      src/main.js
  37. 71 0
      src/router/index.js
  38. 59 0
      src/store/index.js
  39. 179 0
      src/vendor/Blob.js
  40. 141 0
      src/vendor/Export2Excel.js
  41. 0 0
      static/.gitkeep
  42. 二進制
      static/images/add.png
  43. 二進制
      static/images/bb.png
  44. 二進制
      static/images/bg.png
  45. 二進制
      static/images/diwen.png
  46. 二進制
      static/images/exit.png
  47. 二進制
      static/images/huodongcehua.png
  48. 二進制
      static/images/info.png
  49. 二進制
      static/images/logo.png
  50. 二進制
      static/images/mima.png
  51. 二進制
      static/images/renshuyujing.png
  52. 二進制
      static/images/touxiang.jpg
  53. 二進制
      static/images/xiaofeizhanbi.png
  54. 二進制
      static/images/xinwenjujiao.png
  55. 二進制
      static/images/yonghuguanli.png
  56. 二進制
      static/images/yonghuming.png
  57. 二進制
      static/images/zhengfangti.png
  58. 13 0
      static/interface/index.js
  59. 27 0
      test/e2e/custom-assertions/elementCount.js
  60. 46 0
      test/e2e/nightwatch.conf.js
  61. 48 0
      test/e2e/runner.js
  62. 19 0
      test/e2e/specs/test.js
  63. 7 0
      test/unit/.eslintrc
  64. 30 0
      test/unit/jest.conf.js
  65. 3 0
      test/unit/setup.js
  66. 11 0
      test/unit/specs/HelloWorld.spec.js

+ 43 - 0
.babelrc

@@ -0,0 +1,43 @@
+{
+  "presets": [
+    [
+      "es2015",
+      {
+        "modules": false
+      }
+    ],
+    [
+      "env",
+      {
+        "modules": false,
+        "targets": {
+          "browsers": [
+            "> 1%",
+            "last 2 versions",
+            "not ie <= 8"
+          ]
+        }
+      }
+    ],
+    "stage-2"
+  ],
+  "plugins": [
+    "transform-vue-jsx",
+    "transform-runtime",
+    [
+      "component",
+      {
+        "libraryName": "element-ui",
+        "styleLibraryName": "theme-chalk"
+      }
+    ]
+  ],
+  "env": {
+    "test": {
+      "presets": [
+        "env",
+        "stage-2"
+      ]
+    }
+  }
+}

+ 9 - 0
.editorconfig

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

+ 5 - 0
.eslintignore

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

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

+ 17 - 0
.gitignore

@@ -0,0 +1,17 @@
+.DS_Store
+node_modules/
+/dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+/test/unit/coverage/
+/test/e2e/reports/
+selenium-debug.log
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln

+ 10 - 0
.postcssrc.js

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

+ 41 - 0
build/build.js

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

+ 54 - 0
build/check-versions.js

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

+ 101 - 0
build/utils.js

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

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

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

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

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

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

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

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

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

+ 7 - 0
config/dev.env.js

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

+ 96 - 0
config/index.js

@@ -0,0 +1,96 @@
+'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: '/travel/',
+    // 后端请求地址代理,配置后testIp再之后的页面调用时就直接指代 http://197.82.15.15:8088
+    proxyTable: {
+      '/bigData2': {
+        target: 'http://58.17.42.179:90/bigData2', // 你请求的第三方接口
+        // target: 'http://baibai.natapp1.cc', // 你请求的第三方接口
+        changeOrigin: true, // 在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题
+        // pathRewrite: { // 路径重写,
+        //   '^/bigData': '' // 替换target中的请求地址,也就是说以后你在请求http://api.douban.com/v2/XXXXX这个地址的时候直接写成/api即可。
+        // }
+      },
+      '/diseaseRight': {
+        // target: 'http://192.168.161.230:8089/disease-command',
+        target: 'http://58.17.42.179:90/diseaseRight',
+        // target: 'http://chuanghai-dev.natapp1.cc/disease-command',
+        changeOrigin: true,
+        pathRewrite: {
+          '^/diseaseRight': ''
+        }
+      }
+    },
+
+    // Various Dev Server settings
+    host: 'localhost', // can be overwritten by process.env.HOST
+    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
+    autoOpenBrowser: false,
+    errorOverlay: true,
+    notifyOnErrors: true,
+    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
+
+    // Use Eslint Loader?
+    // If true, your code will be linted during bundling and
+    // linting errors and warnings will be shown in the console.
+    useEslint: false,
+    // If true, eslint errors and warnings will also be shown in the error overlay
+    // in the browser.
+    showEslintErrorsInOverlay: false,
+
+    /**
+     * Source Maps
+     */
+
+    // https://webpack.js.org/configuration/devtool/#development
+    devtool: 'cheap-module-eval-source-map',
+
+    // If you have problems debugging vue-files in devtools,
+    // set this to false - it *may* help
+    // https://vue-loader.vuejs.org/en/options.html#cachebusting
+    cacheBusting: true,
+
+    cssSourceMap: true
+  },
+
+  build: {
+    // Template for index.html
+    index: path.resolve(__dirname, '../dist/index.html'),
+    // index: path.resolve('C:/Users/38304/Desktop/dist/index.html'),
+
+    // Paths
+    assetsRoot: path.resolve(__dirname, '../dist'),
+    // assetsRoot: path.resolve('C:/Users/38304/Desktop/dist'),
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/travel/',
+
+    /**
+     * Source Maps
+     */
+
+    productionSourceMap: false,
+    // https://webpack.js.org/configuration/devtool/#production
+    devtool: '#source-map',
+
+    // Gzip off by default as many popular static hosts such as
+    // Surge or Netlify already gzip all static assets for you.
+    // Before setting to `true`, make sure to:
+    // npm install --save-dev compression-webpack-plugin
+    productionGzip: false,
+    productionGzipExtensions: ['js', 'css'],
+
+    // Run the build command with an extra argument to
+    // View the bundle analyzer report after build finishes:
+    // `npm run build --report`
+    // Set to `true` or `false` to always turn it on or off
+    bundleAnalyzerReport: process.env.npm_config_report
+  }
+}

+ 4 - 0
config/prod.env.js

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

+ 7 - 0
config/test.env.js

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

+ 15 - 0
index.html

@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+	<meta charset="utf-8">
+	<meta name="viewport" content="width=device-width,initial-scale=1.0">
+	<title>靖安县数据上传平台</title>
+</head>
+
+<body>
+	<div id="app"></div>
+	<!-- built files will be auto injected -->
+</body>
+
+</html>

File diff suppressed because it is too large
+ 38677 - 0
package-lock.json


+ 98 - 0
package.json

@@ -0,0 +1,98 @@
+{
+  "name": "hot-water-manager-web",
+  "version": "1.0.0",
+  "description": "hotWaterManagerWeb",
+  "author": "小新 <1452635110@qq.com>",
+  "private": true,
+  "scripts": {
+    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --host 0.0.0.0",
+    "start": "npm run dev",
+    "unit": "jest --config test/unit/jest.conf.js --coverage",
+    "e2e": "node test/e2e/runner.js",
+    "test": "npm run unit && npm run e2e",
+    "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs",
+    "build": "node build/build.js"
+  },
+  "dependencies": {
+    "ant-design-vue": "^1.7.7",
+    "axios": "^0.21.1",
+    "echarts": "^4.9.0",
+    "element-ui": "^2.15.5",
+    "file-saver": "^2.0.5",
+    "vue": "^2.5.2",
+    "vue-quill-editor": "^3.0.6",
+    "vue-router": "^3.0.1",
+    "xlsx": "^0.17.5"
+  },
+  "devDependencies": {
+    "autoprefixer": "^7.1.2",
+    "babel-core": "^6.22.1",
+    "babel-eslint": "^8.2.1",
+    "babel-helper-vue-jsx-merge-props": "^2.0.3",
+    "babel-jest": "^21.0.2",
+    "babel-loader": "^7.1.1",
+    "babel-plugin-component": "^1.1.1",
+    "babel-plugin-dynamic-import-node": "^1.2.0",
+    "babel-plugin-import": "^1.13.3",
+    "babel-plugin-syntax-jsx": "^6.18.0",
+    "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
+    "babel-plugin-transform-runtime": "^6.22.0",
+    "babel-plugin-transform-vue-jsx": "^3.5.0",
+    "babel-preset-env": "^1.3.2",
+    "babel-preset-es2015": "^6.24.1",
+    "babel-preset-stage-2": "^6.22.0",
+    "babel-register": "^6.22.0",
+    "chalk": "^2.0.1",
+    "chromedriver": "^2.27.2",
+    "copy-webpack-plugin": "^4.0.1",
+    "cross-spawn": "^5.0.1",
+    "css-loader": "^0.28.0",
+    "eslint": "^4.15.0",
+    "eslint-config-standard": "^10.2.1",
+    "eslint-friendly-formatter": "^3.0.0",
+    "eslint-loader": "^1.7.1",
+    "eslint-plugin-import": "^2.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",
+    "jest": "^22.0.4",
+    "jest-serializer-vue": "^0.3.0",
+    "nightwatch": "^0.9.12",
+    "node-notifier": "^5.1.2",
+    "optimize-css-assets-webpack-plugin": "^3.2.0",
+    "ora": "^1.2.0",
+    "portfinder": "^1.0.13",
+    "postcss-import": "^11.0.0",
+    "postcss-loader": "^2.0.8",
+    "postcss-url": "^7.2.1",
+    "rimraf": "^2.6.0",
+    "script-loader": "^0.7.2",
+    "selenium-server": "^3.0.1",
+    "semver": "^5.3.0",
+    "shelljs": "^0.7.6",
+    "uglifyjs-webpack-plugin": "^1.1.1",
+    "url-loader": "^0.5.8",
+    "vue-jest": "^1.0.2",
+    "vue-loader": "^13.3.0",
+    "vue-style-loader": "^3.0.1",
+    "vue-template-compiler": "^2.5.2",
+    "webpack": "^3.6.0",
+    "webpack-bundle-analyzer": "^2.9.0",
+    "webpack-dev-server": "^2.9.1",
+    "webpack-merge": "^4.1.0"
+  },
+  "engines": {
+    "node": ">= 6.0.0",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
+}

+ 83 - 0
src/App.vue

@@ -0,0 +1,83 @@
+<template>
+  <div id="app">
+    <router-view></router-view>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "App",
+  created() {
+    this.getIp();
+  },
+  methods: {
+    async getIp() {
+      let res = await this.$axios({
+        url: "http://ip-api.com/json",
+        method: "get",
+      });
+      // console.log(res);
+      if (res.status == 200) {
+        let IP = res.data.query;
+        // console.log(IP);
+        let ipList = [
+          "58.17.42.179",
+          "10.201.5.31",
+          "10.205.64.222",
+          "171.34.215.31",
+          "182.105.82.9",
+          "220.175.60.46",
+          "39.160.30.198",
+        ];
+        let isip = ipList.includes(IP);
+        let isip2 = IP.indexOf("218.64.4") > -1;
+        if (!isip && !isip2) {
+          alert("没有访问权限");
+          this.closeWin();
+        }
+      }
+    },
+    closeWin() {
+      if (
+        navigator.userAgent.indexOf("Firefox") != -1 ||
+        navigator.userAgent.indexOf("Chrome") != -1
+      ) {
+        window.location.href =
+          "https://www.baidu.com" + "?v=" + new Date().getTime();
+        window.location.href = "about:blank";
+        window.close();
+      } else {
+        let iphone = navigator.userAgent.toLowerCase().indexOf("iphone");
+        let ipad = navigator.userAgent.toLowerCase().indexOf("ipad");
+        if (iphone != -1 || ipad != -1) {
+          window.location =
+            "https://www.baidu.com" + "?v=" + new Date().getTime();
+        }
+        window.location.href =
+          "https://www.baidu.com" + "?v=" + new Date().getTime();
+        window.opener = null;
+        window.open("", "_self");
+        window.close();
+      }
+    },
+  },
+};
+</script>
+
+<style>
+html,
+body,
+#app {
+  padding: 0;
+  margin: 0;
+  height: calc(100vh);
+  width: 100%;
+  background-color: #eaeaea;
+}
+a {
+  text-decoration: none;
+}
+.el-tooltip__popper {
+  max-width: 80%;
+}
+</style>

二進制
src/assets/logo.png


+ 160 - 0
src/components/consumption/index.vue

@@ -0,0 +1,160 @@
+<template>
+  <div>
+    <!-- 标题 -->
+    <el-row>
+      <el-col
+        :span="24"
+        class="first-row"
+      >
+        <div class="tag">消费占比</div>
+      </el-col>
+    </el-row>
+
+    <!-- 分割线 -->
+    <hr style="background-color: #CCCCCC;height: 1px;border: 0;">
+    <div style="margin: 32px 0;"></div>
+
+    <el-row>
+      <el-col
+        v-for="item in list"
+        :key="item.id"
+        :span="9"
+        style="marginTop: 32px"
+      >
+        <el-col :span="8">
+          <span>{{item.id}}、{{item.categoryName}}</span>
+        </el-col>
+
+        <el-input
+          class="input-new-tag"
+          v-if="item.show"
+          v-model="inputValue"
+          v-fo
+          size="small"
+          @blur="handleInputConfirm(item)"
+        >
+        </el-input>
+        <el-button
+          v-else
+          class="button-new-tag"
+          size="small"
+          @click="showInput(item)"
+        >{{item.value}}</el-button>
+        万
+
+      </el-col>
+    </el-row>
+
+  </div>
+</template>
+
+<script>
+export default {
+  name: "",
+  data() {
+    return {
+      inputValue: "",
+      updateId: "",
+      list: [],
+    };
+  },
+  mounted() {
+    this.getData();
+  },
+  methods: {
+    // 获取消费占比数据
+    async getData() {
+      let res = await this.$axios.get(
+        "/diseaseRight/consumptionCategoryStatistics/list"
+      );
+      // console.log(res);
+      if (res.data.success) {
+        let newArr = [];
+        res.data.data.forEach((element) => {
+          newArr.push({
+            id: element.id,
+            categoryName: element.categoryName,
+            value: Math.round(element.value),
+            show: false,
+          });
+        });
+        this.list = newArr;
+      } else {
+        console.log("获取 消费占比数据 失败");
+      }
+    },
+    // 修改消费占比数据
+    async amendData() {
+      let data = {
+        id: this.updateId,
+        value: this.inputValue,
+      };
+      let res = await this.$axios({
+        url: "/diseaseRight/consumptionCategoryStatistics/update",
+        method: "put",
+        data,
+        headers: {
+          "Admin-Token": sessionStorage.getItem("token"),
+        },
+      });
+      // console.log(res);
+      if (res.data.success) {
+        this.$message({
+          showClose: true,
+          message: "修改成功",
+          type: "success",
+        });
+        this.getData();
+      } else {
+        this.$message({
+          showClose: true,
+          message: "修改失败",
+          type: "error",
+        });
+        this.getData();
+      }
+    },
+    // 点击按钮 切换输入框 并聚焦
+    showInput(i) {
+      i.show = true;
+    },
+    // 失去焦点 切换回按钮 并更新数据
+    handleInputConfirm(i) {
+      this.updateId = i.id;
+      i.show = false;
+      i.value = this.inputValue;
+      this.amendData();
+      this.inputValue = "";
+    },
+  },
+};
+</script>
+
+<style  scoped>
+.first-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  height: 50px;
+}
+.tag {
+  width: 108px;
+  height: 40px;
+  font-size: 24px;
+  font-family: Microsoft YaHei-3970(82674968);
+  font-weight: bold;
+  color: #000000;
+  line-height: 54px;
+}
+.input-new-tag {
+  margin-right: 10px;
+  width: 90px;
+  vertical-align: middle;
+}
+.button-new-tag {
+  margin-right: 10px;
+  width: 90px;
+  height: 32px;
+  vertical-align: middle;
+}
+</style>

+ 200 - 0
src/components/earlyWarning/index.vue

@@ -0,0 +1,200 @@
+<template>
+  <div>
+    <!-- 标题 -->
+    <el-row>
+      <el-col
+        :span="24"
+        class="first-row"
+      >
+        <div class="tag">旅游人数预警</div>
+      </el-col>
+    </el-row>
+
+    <div style="margin: 20px 0;"></div>
+    <hr style="background-color: #CCCCCC;height: 1px;border: 0;">
+
+    <!-- 景点列表 -->
+    <el-row>
+      <el-col
+        v-for="item in list"
+        :key="item.id"
+        :span="8"
+        style="marginTop: 32px;lineHeight:100%"
+      >
+        <el-col :span="12">
+          <span>{{item.place_index}}、{{item.place_name}}</span>
+        </el-col>
+
+        <el-input
+          class="input-new-tag"
+          v-if="item.show"
+          v-model="inputValue"
+          v-fo
+          size="small"
+          @blur="handleInputConfirm(item)"
+        >
+        </el-input>
+        <el-button
+          v-else
+          class="button-new-tag"
+          size="small"
+          @click="showInput(item)"
+        >{{item.maxnum}}</el-button>
+        人
+
+      </el-col>
+    </el-row>
+
+    <div style="margin: 40px 0;"></div>
+
+    <!-- 分页器 -->
+    <el-row>
+
+      <div class="pagination_smoke">
+        <el-pagination
+          background
+          layout="prev, pager, next"
+          :total="totalCount"
+          :page-size="pageSize"
+          :current-page.sync="curPage"
+          @current-change="changeCurPage"
+        >
+        </el-pagination>
+      </div>
+
+    </el-row>
+
+  </div>
+</template>
+
+<script>
+export default {
+  name: "",
+  data() {
+    return {
+      inputValue: "", // 输入框绑定数据
+      list: [], // 景点列表
+      form: {
+        place_name: "", // 景点名称
+        maxnum: "", // 最大容量 单位:人
+      },
+      curPage: 1, // 当前页
+      pageSize: 21, // 每页记录数
+      totalCount: null, // 总条数
+      // place_name: "", // 景点选择框绑定数据
+    };
+  },
+  mounted() {
+    this.getData();
+  },
+  methods: {
+    // 获取乡镇列表列表数据
+    async getData() {
+      let res = await this.$axios.post("/bigData2/tourqueryTourPlace.action");
+      // console.log(res);
+      if (res.status == 200) {
+        let newArr = [];
+        res.data.data.forEach((element, index) => {
+          newArr.push({
+            id: element.id,
+            maxnum: element.maxnum,
+            place_name: element.place_name,
+            show: false,
+            place_index: index + 1,
+          });
+        });
+        if (this.curPage == 1) {
+          this.totalCount = newArr.length;
+          this.list = newArr.splice(0, 21);
+        } else {
+          this.totalCount = newArr.length;
+          this.list = newArr.splice(21, 15);
+        }
+      } else {
+        console.log("获取 活动策划列表数据 失败");
+      }
+    },
+
+    // 修改景点数据
+    async amendPlaceNum() {
+      let res = await this.$axios({
+        url: "/bigData2/tourupdateMaxt.action",
+        method: "post",
+        params: this.form,
+        // headers: {
+        //   "Admin-Token": sessionStorage.getItem("token"),
+        // },
+      });
+      // console.log(res);
+      if (res.data.statusCode == 200) {
+        this.$message({
+          showClose: true,
+          message: "修改成功",
+          type: "success",
+        });
+      } else {
+        this.$message({
+          showClose: true,
+          message: "修改失败",
+          type: "error",
+        });
+      }
+      this.getData();
+    },
+
+    // 点击按钮 切换输入框 并聚焦
+    showInput(i) {
+      i.show = true;
+    },
+    // 失去焦点或者回车 切换回按钮框 并更新数据
+    handleInputConfirm(i) {
+      i.maxnum = this.inputValue;
+      this.form.place_name = i.place_name;
+      this.form.maxnum = i.maxnum;
+      i.show = false;
+      this.amendPlaceNum();
+      this.inputValue = "";
+    },
+    // 换页逻辑
+    changeCurPage(val) {
+      // console.log(`当前页: ${val}`);
+      this.curPage = val;
+      this.getData();
+    },
+  },
+};
+</script>
+
+<style scoped>
+.first-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  height: 50px;
+}
+.tag {
+  width: 208px;
+  height: 40px;
+  font-size: 24px;
+  font-family: Microsoft YaHei-3970(82674968);
+  font-weight: bold;
+  color: #000000;
+  line-height: 54px;
+}
+.input-new-tag {
+  margin-right: 10px;
+  width: 90px;
+  vertical-align: middle;
+}
+.button-new-tag {
+  margin-right: 10px;
+  width: 90px;
+  height: 32px;
+  vertical-align: middle;
+}
+.pagination_smoke {
+  position: absolute;
+  top: 60px;
+  left: 565px;
+}
+</style>

+ 797 - 0
src/components/eventPlanning/index.vue

@@ -0,0 +1,797 @@
+<template>
+  <div>
+    <!-- 标题 -->
+    <el-row class="first-row">
+      <div class="tag">活动策划</div>
+    </el-row>
+
+    <!-- 分割线 -->
+    <hr style="background-color: #CCCCCC;height: 1px;border: 0;">
+
+    <el-tabs>
+      <!-- 策划内容区域 -->
+      <el-tab-pane label="策划内容">
+        <!-- 时间选择器和增加按钮 -->
+        <el-row style="marginTop:10px">
+          <el-col :span="6">
+            <el-date-picker
+              v-model="select_datetime"
+              type="daterange"
+              align="center"
+              unlink-panels
+              range-separator="至"
+              @change="dateChange"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              class="shijian_plus"
+            >
+            </el-date-picker>
+          </el-col>
+          <el-col :span="6">
+            <el-button
+              type="primary"
+              icon="el-icon-plus"
+              @click="dialogFormVisible = true;form = {};"
+            >添加活动策划</el-button>
+          </el-col>
+        </el-row>
+
+        <div style="margin: 20px 0;"></div>
+        <hr style="background-color: #CCCCCC;height: 1px;border: 0;">
+
+        <!-- 表格区域 -->
+        <el-row>
+          <el-table
+            :data="tableData"
+            highlight-current-row
+            height="450"
+            v-loading="loading"
+            element-loading-text="加载中"
+            element-loading-spinner="el-icon-loading"
+          >
+            <el-table-column
+              prop="title"
+              label="标题"
+              align="center"
+              width="300"
+              show-overflow-tooltip
+            >
+            </el-table-column>
+            <el-table-column
+              prop="startTime"
+              label="时间"
+              align="center"
+              width="220"
+            >
+            </el-table-column>
+            <el-table-column
+              prop="content"
+              label="内容"
+              align="center"
+              show-overflow-tooltip
+            >
+            </el-table-column>
+
+            <el-table-column
+              label="操作"
+              align="center"
+              width="200"
+            >
+              <template slot-scope="{ row }">
+                <el-button
+                  type="warning"
+                  size="mini"
+                  @click="amendEventPlanning(row)"
+                >编辑</el-button>
+                <el-button
+                  type="danger"
+                  size="mini"
+                  @click="deleteEventPlanning(row.id)"
+                >删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-row>
+
+        <div style="margin: 20px 0;"></div>
+
+        <!-- 分页器 -->
+        <el-row>
+          <div class="pagination_smoke">
+            <el-pagination
+              background
+              layout="prev, pager, next"
+              :total="totalCount"
+              :page-size="pageSize"
+              :current-page.sync="curPage"
+              @current-change="changeCurPage"
+            >
+            </el-pagination>
+          </div>
+
+        </el-row>
+      </el-tab-pane>
+
+      <!-- 月度小结区域 -->
+      <el-tab-pane label="月度小结">
+        <!-- 时间日期选择器和增加按钮 -->
+        <el-row style="marginTop:10px">
+          <el-col :span="6">
+            <el-date-picker
+              v-model="select_datetime2"
+              type="month"
+              value-format="yyyy-MM"
+              placeholder="选择月份筛选"
+              @change="getData2"
+            >
+            </el-date-picker>
+          </el-col>
+          <el-col :span="6">
+            <el-button
+              type="primary"
+              icon="el-icon-plus"
+              @click="handleAdd"
+            >添加月度小结</el-button>
+          </el-col>
+        </el-row>
+
+        <div style="margin: 20px 0;"></div>
+        <hr style="background-color: #CCCCCC;height: 1px;border: 0;">
+
+        <!-- 表格区域 -->
+        <el-row>
+          <el-table
+            :data="tableData2"
+            highlight-current-row
+            height="450"
+            v-loading="loading"
+            element-loading-text="加载中"
+            element-loading-spinner="el-icon-loading"
+          >
+            <el-table-column
+              prop="month"
+              label="时间"
+              align="center"
+              width="120"
+            >
+            </el-table-column>
+            <el-table-column
+              prop="title"
+              label="标题"
+              align="center"
+              width="220"
+              show-overflow-tooltip
+            >
+            </el-table-column>
+            <el-table-column
+              label="内容"
+              align="center"
+              show-overflow-tooltip
+            >
+              <template slot-scope="{row}">
+                <div
+                  style="height:25px"
+                  v-html="row.content"
+                ></div>
+              </template>
+            </el-table-column>
+
+            <el-table-column
+              label="操作"
+              align="center"
+              width="200"
+            >
+              <template slot-scope="{ row }">
+                <el-button
+                  type="warning"
+                  size="mini"
+                  @click="editNodulus(row)"
+                >编辑</el-button>
+                <el-button
+                  type="danger"
+                  size="mini"
+                  @click="deleteNodulus(row)"
+                >删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-row>
+
+        <div style="margin: 20px 0;"></div>
+
+        <!-- 分页器 -->
+        <el-row>
+          <div class="pagination_smoke">
+            <el-pagination
+              background
+              layout="prev, pager, next"
+              :total="totalCount2"
+              :page-size="pageSize2"
+              :current-page.sync="curPage2"
+              @current-change="changeCurPage2"
+            >
+            </el-pagination>
+          </div>
+
+        </el-row>
+
+      </el-tab-pane>
+    </el-tabs>
+
+    <!-- 新增 活动策划 弹窗 -->
+    <el-dialog
+      title="添加活动策划"
+      :visible.sync="dialogFormVisible"
+      :close-on-click-modal="false"
+      center
+      style="width:90%"
+    >
+      <el-form
+        :model="form"
+        :rules="rules"
+        ref="form"
+        style="width:80%"
+        label-width="80px"
+      >
+        <el-form-item
+          label="时间"
+          prop="startTime"
+        >
+          <el-date-picker
+            v-model="form.startTime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            type="datetime"
+            placeholder="选择日期时间"
+          >
+          </el-date-picker>
+        </el-form-item>
+
+        <el-form-item
+          label="标题"
+          prop="title"
+        >
+          <el-input v-model="form.title"></el-input>
+        </el-form-item>
+
+        <el-form-item
+          label="内容"
+          prop="content"
+        >
+          <el-input
+            type="textarea"
+            :autosize="{ minRows: 4, maxRows: 6}"
+            v-model="form.content"
+          ></el-input>
+        </el-form-item>
+
+      </el-form>
+      <div
+        slot="footer"
+        class="dialog-footer"
+      >
+        <el-button
+          type="primary"
+          @click="addEventPlanning('form')"
+        >确 定</el-button>
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 修改 活动策划 弹窗 -->
+    <el-dialog
+      title="修改活动策划"
+      :visible.sync="dialogFormVisible2"
+      :close-on-click-modal="false"
+      center
+      style="width:90%"
+    >
+      <el-form
+        :model="form"
+        style="width:80%"
+        label-width="80px"
+      >
+
+        <el-form-item label="时间">
+          <el-date-picker
+            v-model="form.startTime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            type="datetime"
+            placeholder="选择日期时间"
+          >
+          </el-date-picker>
+        </el-form-item>
+
+        <el-form-item label="标题">
+          <el-input v-model="form.title"></el-input>
+        </el-form-item>
+
+        <el-form-item label="内容">
+          <el-input
+            type="textarea"
+            :autosize="{ minRows: 4, maxRows: 6}"
+            v-model="form.content"
+          ></el-input>
+        </el-form-item>
+
+      </el-form>
+
+      <div
+        slot="footer"
+        class="dialog-footer"
+      >
+        <el-button
+          type="primary"
+          @click="hangdleAmendEventPlanning"
+        >确 定</el-button>
+        <el-button @click="dialogFormVisible2 = false">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 新增或编辑 月度小结 弹窗 -->
+    <el-dialog
+      :title="title"
+      :visible.sync="dialogFormVisible3"
+      :close-on-click-modal="false"
+      center
+      style="width:90%"
+    >
+      <el-form
+        :model="form2"
+        :rules="rules2"
+        ref="form2"
+        style="width:80%"
+        label-width="80px"
+      >
+        <el-form-item
+          label="时间"
+          prop="month"
+        >
+          <el-date-picker
+            v-model="form2.month"
+            value-format="yyyy-MM"
+            type="month"
+            placeholder="选择时间"
+          >
+          </el-date-picker>
+        </el-form-item>
+
+        <el-form-item
+          label="标题"
+          prop="title"
+        >
+          <el-input v-model="form2.title"></el-input>
+        </el-form-item>
+
+        <el-form-item
+          label="内容"
+          prop="content"
+        >
+          <quill-editor
+            ref="QuillEditor"
+            v-model="form2.content"
+            style="height: 200px;marginBottom:20px"
+            :options="editorOption"
+          >
+          </quill-editor>
+
+          <el-upload
+            v-show="false"
+            class="avatar-uploader"
+            name="img"
+            action="#"
+            :auto-upload="false"
+            :show-file-list="false"
+            :on-change="getLocalImg"
+          >
+          </el-upload>
+
+        </el-form-item>
+
+      </el-form>
+      <div
+        slot="footer"
+        class="dialog-footer"
+      >
+        <el-button
+          type="primary"
+          @click="handleAddOrUpdata('form2')"
+        >确 定</el-button>
+        <el-button @click="dialogFormVisible3 = false">取 消</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+// 引入富文本编辑框和样式
+import { quillEditor } from "vue-quill-editor";
+import "quill/dist/quill.core.css";
+import "quill/dist/quill.snow.css";
+import "quill/dist/quill.bubble.css";
+export default {
+  name: "EventPlanning",
+  components: { quillEditor },
+  data() {
+    return {
+      select_datetime: [], // 策划内容选择的时间范围
+      select_datetime2: "", // 月度小结选择的时间范围
+      startTime: "", // 开始时间
+      endTime: "", // 结束时间
+
+      tableData: [], // 策划内容表格数据
+      curPage: 1, // 当前页
+      pageSize: 7, // 每页记录数
+      totalCount: null, // 总条数
+
+      tableData2: [], // 月度小结表格数据
+      curPage2: 1, // 当前页
+      pageSize2: 6, // 每页记录数
+      totalCount2: null, // 总条数
+
+      dialogFormVisible: false,
+      dialogFormVisible2: false,
+      dialogFormVisible3: false,
+      form: {
+        title: "", // 标题
+        startTime: "", // 时间
+        content: "", // 内容
+      },
+      rules: {
+        title: [{ required: true, message: "请输入标题", trigger: "blur" }],
+        startTime: [{ required: true, message: "请选择时间", trigger: "blur" }],
+        content: [{ required: true, message: "请输入内容", trigger: "blur" }],
+      },
+      form2: {
+        title: "", // 标题
+        month: "", // 时间
+        content: "", // 内容
+      },
+      rules2: {
+        title: [{ required: true, message: "请输入标题", trigger: "blur" }],
+        month: [{ required: true, message: "请选择时间", trigger: "blur" }],
+        content: [{ required: true, message: "请输入内容", trigger: "blur" }],
+      },
+      // 富文本自定义
+      editorOption: {
+        placeholder: "请输入内容",
+        modules: {
+          toolbar: {
+            container: [
+              ["bold", "italic", "underline", "strike"], //加粗,斜体,下划线,删除线
+              [{ indent: "-1" }, { indent: "+1" }], // 缩进
+              ["image"],
+              ["clean"], //清除字体样式
+            ],
+            handlers: {
+              image: function (value) {
+                if (value) {
+                  // 调用element的图片上传组件
+                  document.querySelector(".avatar-uploader input").click();
+                } else {
+                  this.quill.format("image", false);
+                }
+              },
+            },
+          },
+        },
+      },
+      title: "",
+      loading: false,
+    };
+  },
+  mounted() {
+    this.getData();
+    this.getData2();
+  },
+  methods: {
+    // 获取活动策划列表数据
+    async getData() {
+      this.loading = true;
+      let params = {
+        curPage: this.curPage,
+        pageSize: this.pageSize,
+        startTime: this.startTime,
+        endTime: this.endTime,
+      };
+      let res = await this.$axios({
+        url: "/diseaseRight/eventPlanning/list",
+        method: "get",
+        params,
+      });
+      // console.log(res);
+      if (res.data.success) {
+        this.tableData = res.data.data.list;
+        this.totalCount = res.data.data.totalCount;
+      } else {
+        console.log("获取 活动策划列表数据 失败");
+      }
+      this.loading = false;
+    },
+    // 添加活动策划
+    addEventPlanning(formName) {
+      this.$refs[formName].validate(async (valid) => {
+        if (valid) {
+          this.dialogFormVisible = false;
+          let res = await this.$axios({
+            method: "post",
+            url: "/diseaseRight/eventPlanning/save",
+            headers: {
+              "Admin-Token": sessionStorage.getItem("token"),
+            },
+            data: this.form,
+          });
+          // console.log(res);
+          if (res.data.success) {
+            this.handleCurrentChange(1);
+            this.$message.success("添加成功!");
+          } else {
+            this.$message.error("添加失败!");
+          }
+        } else {
+          console.log("提交失败!!");
+          return false;
+        }
+      });
+    },
+    // 修改活动策划
+    amendEventPlanning(row) {
+      this.form = { ...row };
+      this.dialogFormVisible2 = true;
+    },
+    // 修改活动策划请求
+    async hangdleAmendEventPlanning() {
+      this.dialogFormVisible2 = false;
+      let res = await this.$axios({
+        method: "put",
+        url: "/diseaseRight/eventPlanning/update",
+        headers: {
+          "Admin-Token": sessionStorage.getItem("token"),
+        },
+        data: this.form,
+      });
+      // console.log(res);
+      if (res.data.success) {
+        this.handleCurrentChange(this.curPage);
+        this.$message.success("修改成功!");
+      } else {
+        this.$message.error("修改失败!");
+      }
+    },
+    // 删除活动策划
+    deleteEventPlanning(id) {
+      this.$confirm("确定删除吗?", "提示", {
+        cancelButtonText: "取消",
+        confirmButtonText: "确定",
+        type: "warning",
+      })
+        .then(async () => {
+          let res = await this.$axios({
+            method: "delete",
+            url: "/diseaseRight/eventPlanning/delete",
+            headers: {
+              "Admin-Token": sessionStorage.getItem("token"),
+            },
+            data: [id],
+          });
+          // console.log(res);
+          if (res.data.success) {
+            this.$message.success("删除成功");
+            let totalPage = Math.ceil((this.totalCount - 1) / this.pageSize);
+            let currentPage =
+              this.curPage > totalPage ? totalPage : this.curPage;
+            this.curPage = currentPage < 1 ? 1 : currentPage;
+            this.handleCurrentChange(this.curPage);
+          } else {
+            this.$message.error("删除失败!");
+          }
+        })
+        .catch(() => {
+          this.$message.info("已取消");
+        });
+    },
+    // 选择时间范围
+    dateChange(val) {
+      if (val) {
+        this.startTime = val[0];
+        this.endTime = val[1];
+        this.handleCurrentChange(1);
+      } else {
+        this.startTime = "";
+        this.endTime = "";
+        this.handleCurrentChange(1);
+      }
+    },
+    // 策划内容换页逻辑
+    changeCurPage(val) {
+      // console.log(`当前页: ${val}`);
+      this.handleCurrentChange(val);
+    },
+    // 策划内容整理参数
+    handleCurrentChange(val) {
+      this.curPage = val;
+      this.getData();
+    },
+
+    // 获取月度小结列表数据
+    async getData2() {
+      this.loading = true;
+      let params = {
+        curPage: this.curPage2,
+        pageSize: this.pageSize2,
+        month: this.select_datetime2,
+      };
+      let res = await this.$axios({
+        url: "/diseaseRight/eventPlanningMonthSummary/list",
+        method: "get",
+        params,
+      });
+      // console.log(res);
+      if (res.data.success) {
+        this.tableData2 = res.data.data.list;
+        this.totalCount2 = res.data.data.totalCount;
+      } else {
+        console.log("获取 月度小结列表数据 失败");
+      }
+      this.loading = false;
+    },
+    // 添加月度小结按钮回调
+    handleAdd() {
+      this.dialogFormVisible3 = true;
+      this.title = "添加";
+      this.$nextTick(() => {
+        this.$refs.form2.resetFields();
+        this.form2 = {
+          title: "",
+          month: "",
+          content: "",
+        };
+      });
+    },
+    // 编辑按钮回调
+    editNodulus(row) {
+      this.form2 = { ...row };
+      this.dialogFormVisible3 = true;
+      this.title = "编辑";
+    },
+    // 删除按钮回调
+    deleteNodulus(row) {
+      this.$confirm("确定删除吗?", "提示", {
+        cancelButtonText: "取消",
+        confirmButtonText: "确定",
+        type: "warning",
+      })
+        .then(async () => {
+          let res = await this.$axios({
+            method: "delete",
+            url: "/diseaseRight/eventPlanningMonthSummary/delete",
+            headers: {
+              "Admin-Token": sessionStorage.getItem("token"),
+            },
+            data: [row.id],
+          });
+          // console.log(res);
+          if (res.data.success) {
+            this.$message.success("删除成功");
+            let totalPage = Math.ceil((this.totalCount2 - 1) / this.pageSize2);
+            let currentPage =
+              this.curPage2 > totalPage ? totalPage : this.curPage2;
+            this.curPage2 = currentPage < 1 ? 1 : currentPage;
+            this.getData2();
+          } else {
+            this.$message.error("删除失败!");
+          }
+        })
+        .catch(() => {
+          this.$message.info("已取消");
+        });
+    },
+    // 添加或编辑 月度小结 请求
+    handleAddOrUpdata(formName) {
+      this.$refs[formName].validate(async (valid) => {
+        if (valid) {
+          this.dialogFormVisible3 = false;
+          if (this.form2.id) {
+            // 编辑请求
+            let res = await this.$axios({
+              method: "put",
+              url: "/diseaseRight/eventPlanningMonthSummary/update",
+              headers: {
+                "Admin-Token": sessionStorage.getItem("token"),
+              },
+              data: this.form2,
+            });
+            // console.log(res);
+            if (res.data.success) {
+              this.getData2();
+              this.$message.success("编辑成功!");
+            } else {
+              this.$message.error(res.data.message);
+            }
+          } else {
+            // 添加请求
+            let res = await this.$axios({
+              method: "post",
+              url: "/diseaseRight/eventPlanningMonthSummary/save",
+              headers: {
+                "Admin-Token": sessionStorage.getItem("token"),
+              },
+              data: this.form2,
+            });
+            // console.log(res);
+            if (res.data.success) {
+              this.handleCurrentChange2(1);
+              this.$message.success("添加成功!");
+            } else {
+              this.$message.error(res.data.message);
+            }
+          }
+        } else {
+          console.log("提交失败!!");
+          return false;
+        }
+      });
+    },
+    // 月度小结换页逻辑
+    changeCurPage2(val) {
+      this.handleCurrentChange2(val);
+    },
+    // 月度小结整理参数
+    handleCurrentChange2(val) {
+      this.curPage2 = val;
+      this.getData2();
+    },
+    // 富文本插入图片请求
+    async getLocalImg(file) {
+      let formData = new FormData();
+      formData.append("file", file.raw);
+      let res = await this.$axios({
+        url: "/diseaseRight/file/imageUpload",
+        method: "post",
+        data: formData,
+        headers: {
+          "Admin-Token": sessionStorage.getItem("token"),
+        },
+      });
+      // console.log(res);
+      if (res.data.success) {
+        // 获取富文本组件实例
+        let quill = this.$refs.QuillEditor.quill;
+        // 获取光标所在位置
+        let length = quill.getSelection().index;
+        // 插入图片,res为服务器返回的图片链接地址
+        quill.insertEmbed(length, "image", res.data.data.showUrl);
+        // 调整光标到最后
+        quill.setSelection(length + 1);
+        this.$message.success("图片插入成功!");
+      } else {
+        this.$message.error("图片插入失败!");
+      }
+    },
+  },
+};
+</script>
+
+<style scoped>
+.first-row {
+  display: flex;
+  align-items: center;
+  height: 50px;
+}
+.tag {
+  width: 108px;
+  height: 40px;
+  font-size: 24px;
+  font-family: Microsoft YaHei-3970(82674968);
+  font-weight: bold;
+  color: #000000;
+  line-height: 54px;
+}
+.shijian_plus.el-date-editor--daterange {
+  width: 250px;
+}
+.pagination_smoke {
+  text-align: center;
+}
+</style>

+ 291 - 0
src/components/form/index.vue

@@ -0,0 +1,291 @@
+<template>
+  <div>
+    <!-- 标题 -->
+    <el-row class="first-row">
+      <div class="tag">报表</div>
+    </el-row>
+
+    <!-- 分割线 -->
+    <hr style="background-color: #cccccc; height: 1px; border: 0" />
+
+    <el-tabs>
+      <!-- 游客来源地区域 -->
+      <el-tab-pane label="游客来源地统计报表">
+        <!-- 增加按钮和搜索框 -->
+        <el-row style="margintop: 10px">
+          <el-col :span="3">
+            <el-button
+              type="primary"
+              icon="el-icon-download"
+              :disabled="tableData.length == 0"
+              @click="handleExport"
+              >导出</el-button
+            >
+          </el-col>
+
+          <el-col :span="8">
+            时间选择:
+            <el-date-picker
+              v-model="time"
+              type="daterange"
+              range-separator="至"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              value-format="yyyy-MM-dd"
+              :picker-options="pickerOptions"
+              @change="changeTime"
+            >
+            </el-date-picker>
+          </el-col>
+
+          <el-col :span="6">
+            地区选择:
+            <el-select
+              v-model="placeType"
+              placeholder="请选择地区"
+              @change="changePlace"
+              clearable
+            >
+              <el-option
+                v-for="item in options"
+                :key="item.id"
+                :label="item.value"
+                :value="item.value"
+              >
+              </el-option>
+            </el-select>
+          </el-col>
+        </el-row>
+
+        <div style="margin: 20px 0"></div>
+        <hr style="background-color: #cccccc; height: 1px; border: 0" />
+
+        <!-- 表格区域 -->
+        <el-row>
+          <el-table
+            :data="tableData"
+            highlight-current-row
+            height="450"
+            v-loading="loading"
+            element-loading-text="加载中"
+            element-loading-spinner="el-icon-loading"
+          >
+            <el-table-column prop="id" label="排名" align="center" width="100">
+            </el-table-column>
+            <el-table-column prop="province" label="地区" align="center">
+            </el-table-column>
+            <el-table-column label="人数" align="center">
+              <template slot-scope="{ row }">
+                {{ row.num * coefficient }}
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-row>
+
+        <div style="margin: 20px 0"></div>
+
+        <!-- 分页器 -->
+        <el-row>
+          <el-col :span="9" style="margintop: 7px"
+            >合计人数:{{ peopleCount * coefficient }}</el-col
+          >
+          <el-col :span="9">
+            <el-pagination
+              background
+              layout="total,prev, pager, next"
+              :total="totalCount"
+              :page-size="pageSize"
+              :current-page.sync="curPage"
+              @current-change="getData"
+            >
+            </el-pagination>
+          </el-col>
+        </el-row>
+      </el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      pickerOptions: {
+        disabledDate(time) {
+          return time.getTime() > Date.now() - 24 * 60 * 60 * 1000;
+        },
+      },
+      placeType: "",
+      time: [],
+      options: [
+        {
+          id: 1,
+          value: "全部",
+        },
+        {
+          id: 2,
+          value: "省内",
+        },
+        {
+          id: 3,
+          value: "省外",
+        },
+      ],
+      tableData: [],
+      loading: false,
+      totalCount: null,
+      pageSize: 999,
+      curPage: 1,
+      startTime: "",
+      endTime: "",
+      placeType: "",
+      peopleCount: "",
+      coefficient: null,
+    };
+  },
+  created() {
+    this.getData_coefficient();
+  },
+  mounted() {
+    this.placeType = "全部";
+    this.initDate();
+    this.getData();
+  },
+  methods: {
+    //  初始化日期时间
+    initDate() {
+      let d = new Date();
+      var year1 = d.getFullYear(); // 获取当前年份
+      var mon1 = d.getMonth() + 1; // 获取当前月份
+      var day1 = d.getDate(); // 获取当前日
+
+      //前一天设定的日期时间
+      d.setTime(d.getTime() - 24 * 60 * 60 * 1000);
+
+      var year2 = d.getFullYear(); // 获取当前年份
+      var mon2 = d.getMonth() + 1; // 获取当前月份
+      var day2 = d.getDate(); // 获取当前日
+
+      this.startTime = this.getDate(year2, mon2, day2);
+      this.endTime = this.getDate(year1, mon1, day1);
+
+      this.time.push(this.startTime);
+      this.time.push(this.endTime);
+    },
+
+    // 获取指定格式 年、月、日
+    getDate(y, m, d) {
+      m = m > 9 ? m : "0" + m;
+      d = d > 9 ? d : "0" + d;
+      return y + "-" + m + "-" + d;
+    },
+
+    // 获取 基础系数 数据
+    async getData_coefficient() {
+      let res = await this.$axios.post("/bigData2/tourqueryTourx.action");
+      // console.log(res);
+      if (res.status == 200) {
+        res.data.data.forEach((element) => {
+          if (element.xs_name == "游客来源地") {
+            this.coefficient = element.xs2;
+          }
+        });
+        console.log(this.coefficient);
+      } else {
+        console.log("获取 基础系数数据 失败");
+      }
+    },
+
+    // 获取报表数据
+    async getData() {
+      let params = {
+        page: this.curPage,
+        rows: this.pageSize,
+        startTime: this.startTime,
+        endTime: this.endTime,
+        lei: this.placeType,
+      };
+      let res = await this.$axios({
+        url: "/bigData2/tourprovincePage.action",
+        method: "post",
+        params,
+      });
+      // console.log(res);
+      if (res.status == 200) {
+        this.peopleCount = null;
+        this.tableData = res.data.rows;
+        this.totalCount = res.data.total;
+        if (res.data.rows.length != 0) {
+          res.data.rows.forEach((element) => {
+            this.peopleCount += element.num - 0;
+          });
+        }
+      } else {
+        console.log("获取 报表数据 失败");
+      }
+    },
+
+    changePlace(val) {
+      this.curPage = 1;
+      if (val) {
+        this.getData();
+      } else {
+        this.placeType = "全部";
+        this.getData();
+      }
+    },
+
+    changeTime(val) {
+      this.curPage = 1;
+      if (val) {
+        this.startTime = val[0];
+        this.endTime = val[1];
+        this.getData();
+      } else {
+        this.$message.error("请选择筛选时间");
+        this.tableData = [];
+        this.totalCount = null;
+        this.peopleCount = null;
+      }
+    },
+
+    // 导出按钮回调
+    handleExport() {
+      require.ensure([], () => {
+        // js文件的相对路径
+        const { export_json_to_excel } = require("../../vendor/Export2Excel");
+        // 设置Excel的表格第一行的标题
+        const tHeader = ["排名", "地区", "人数"];
+        // 设置tableData里对象的属性
+        const filterVal = ["id", "province", "num"];
+        //把data里的tableData存到list
+        const list = this.tableData;
+        const data = this.formatJson(filterVal, list);
+        export_json_to_excel(tHeader, data, "游客来源地统计报表");
+      });
+    },
+
+    // 数据处理
+    formatJson(filterVal, jsonData) {
+      return jsonData.map((v) => filterVal.map((j) => v[j]));
+    },
+  },
+};
+</script>
+
+<style scoped>
+.first-row {
+  display: flex;
+  align-items: center;
+  height: 50px;
+}
+.tag {
+  width: 108px;
+  height: 40px;
+  font-size: 24px;
+  font-family: Microsoft YaHei-3970(82674968);
+  font-weight: bold;
+  color: #000000;
+  line-height: 54px;
+}
+</style>>

+ 191 - 0
src/components/index/index.css

@@ -0,0 +1,191 @@
+/* menu */
+.container {
+	width: 100%;
+	height: 100%;
+}
+
+.menu-left {
+	width: 340px;
+	height: 850px;
+	background: #1D3251;
+}
+
+.logo-col,
+.title-col {
+	display: flex;
+	justify-content: center;
+}
+
+.logo {
+	margin-top: 34px;
+	width: 84px;
+	height: 84px;
+	background: url(../../../static/images/logo.png) 0 0 no-repeat;
+	background-size: 84px 84px;
+	opacity: 0;
+}
+
+.title {
+	margin-top: 26px;
+	width: 268px;
+	height: 34px;
+	line-height: 34px;
+	font-size: 20px;
+	font-family: Microsoft YaHei-3970(82674968);
+	font-weight: bold;
+	color: #FFFFFF;
+}
+
+.menu-row {
+	margin-top: 39px;
+	width: 341px;
+}
+
+.el-menu-item {
+	padding-left: 50px !important;
+	height: 60px;
+}
+
+.el-menu-item:hover {
+	background: #134a7a !important;
+}
+
+.el-menu-item.is-active {
+	background: #298DEF !important;
+}
+
+.el-menu-item span {
+	height: 20px;
+	padding-left: 6px;
+	font-size: 22px;
+	font-family: Microsoft YaHei-3970(82674968);
+	font-weight: 400;
+	color: #FFFFFF;
+	line-height: 54px;
+}
+
+.el-menu-item .el-icon-xfzb {
+	width: 27px;
+	height: 27px;
+	background: url(../../../static/images/xiaofeizhanbi.png) center center no-repeat;
+	background-size: cover;
+}
+
+.el-menu-item .el-icon-hdch {
+	width: 27px;
+	height: 27px;
+	background: url(../../../static/images/huodongcehua.png) center center no-repeat;
+	background-size: cover;
+}
+
+.el-menu-item .el-icon-xwjj {
+	width: 27px;
+	height: 27px;
+	background: url(../../../static/images/xinwenjujiao.png) center center no-repeat;
+	background-size: cover;
+}
+
+.el-menu-item .el-icon-rcxs {
+	width: 27px;
+	height: 27px;
+	background: url(../../../static/images/yonghuguanli.png) center center no-repeat;
+	background-size: cover;
+}
+
+.el-menu-item .el-icon-zhfw {
+	width: 27px;
+	height: 27px;
+	background: url(../../../static/images/zhengfangti.png) center center no-repeat;
+	background-size: cover;
+}
+
+.el-menu-item .el-icon-lyrs {
+	width: 27px;
+	height: 27px;
+	background: url(../../../static/images/renshuyujing.png) center center no-repeat;
+	background-size: cover;
+}
+
+.el-menu-item .el-icon-bb {
+	width: 27px;
+	height: 27px;
+	background: url(../../../static/images/bb.png) center center no-repeat;
+	background-size: cover;
+}
+
+.diwen {
+	margin: 30px 0 0 76px;
+	width: 176px;
+	height: 145px;
+	background: url(../../../static/images/diwen.png) no-repeat;
+	background-size: 176px 145px;
+}
+
+/* menu */
+
+/* top */
+.right-top {
+	display: flex;
+	justify-content: space-between;
+	width: 100%;
+	height: 90px;
+	line-height: 90px;
+	background: #FFFFFF;
+}
+
+.wecome-text {
+	width: 300px;
+	height: 90px;
+	line-height: 90px;
+	font-size: 16px;
+	font-family: Microsoft YaHei-3970(82674968);
+	font-weight: 400;
+	color: #333333;
+	padding-left: 34px;
+}
+
+.right-items {
+	display: flex;
+	justify-content: flex-end;
+	align-items: center;
+	padding-right: 51px;
+}
+
+.tx {
+	margin-left: 50px;
+	width: 54px;
+	height: 54px;
+	border-radius: 50%;
+	background: url(../../../static/images/touxiang.jpg) no-repeat;
+	background-size: 54px 54px;
+	border: 1px solid #EEEEEE;
+	cursor: pointer;
+}
+
+.shuxian {
+	width: 1px;
+	height: 36px;
+	background: #CCCCCC;
+	margin: 0 21px 0 23px;
+}
+
+.logout-btn {
+	width: 50px;
+	height: 90px;
+	background: url(../../../static/images/exit.png) center center no-repeat;
+	background-size: 29px 29px;
+	cursor: pointer;
+}
+
+/* top */
+
+/* main */
+.right-main {
+	margin: 20px 1px 0 20px;
+	padding: 20px 50px 28px 50px;
+	width: calc(100% - 40px);
+	height: 740px;
+	background: #FFFFFF;
+}
+
+/* main */

+ 191 - 0
src/components/index/index.vue

@@ -0,0 +1,191 @@
+<template>
+  <el-row
+    type="flex"
+    class="container"
+    justify="space-between"
+  >
+
+    <!-- 左边路由导航 -->
+    <el-col
+      :span="4"
+      class="menu-left"
+    >
+      <el-row>
+        <el-col
+          :span="24"
+          class="logo-col"
+        >
+          <div class="logo"></div>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col
+          :span="24"
+          class="title-col"
+        >
+          <div class="title">旅游大数据上传后台</div>
+        </el-col>
+      </el-row>
+      <!-- 路由选项 -->
+      <el-row class="menu-row">
+        <el-col :span="24">
+          <el-menu
+            router
+            :default-active="$route.path"
+            class="el-menu-vertical-demo"
+            background-color="#1D3251"
+            text-color="#fff"
+            active-text-color="#fff"
+          >
+            <router-link to="consumption">
+              <el-menu-item index="/travel/index/consumption">
+                <i class="el-icon-xfzb"></i>
+                <span slot="title">消费占比</span>
+              </el-menu-item>
+            </router-link>
+
+            <router-link to="eventPlanning">
+              <el-menu-item index="/travel/index/eventPlanning">
+                <i class="el-icon-hdch"></i>
+                <span slot="title">活动策划</span>
+              </el-menu-item>
+            </router-link>
+
+            <router-link to="newsFocus">
+              <el-menu-item index="/travel/index/newsFocus">
+                <i class="el-icon-xwjj"></i>
+                <span slot="title">新闻聚焦</span>
+              </el-menu-item>
+            </router-link>
+
+            <router-link to="peopleCoefficient">
+              <el-menu-item index="/travel/index/peopleCoefficient">
+                <i class="el-icon-rcxs"></i>
+                <span slot="title">人次系数</span>
+              </el-menu-item>
+            </router-link>
+
+            <router-link to="serve">
+              <el-menu-item index="/travel/index/serve">
+                <i class="el-icon-zhfw"></i>
+                <span slot="title">智慧服务</span>
+              </el-menu-item>
+            </router-link>
+
+            <router-link to="earlyWarning">
+              <el-menu-item index="/travel/index/earlyWarning">
+                <i class="el-icon-lyrs"></i>
+                <span slot="title">旅游人数预警</span>
+              </el-menu-item>
+            </router-link>
+
+            <router-link to="form">
+              <el-menu-item index="/travel/index/form">
+                <i class="el-icon-bb"></i>
+                <span slot="title">报表</span>
+              </el-menu-item>
+            </router-link>
+
+          </el-menu>
+        </el-col>
+      </el-row>
+      <div class="diwen"></div>
+    </el-col>
+
+    <!-- 右边展示内容路由导航 -->
+    <el-col :span="20">
+      <el-row>
+        <el-col
+          :span="24"
+          class="right-top"
+        >
+          <div class="wecome-text">{{ userName }} 您好,欢迎登陆!</div>
+          <div class="right-items">
+            <div><a
+                href="http://58.17.42.179:90/travel-explain"
+                target="_blank"
+              >帮助文档</a></div>
+            <div class="tx"></div>
+            <div class="shuxian"></div>
+            <div
+              class="logout-btn"
+              @click="logout"
+            ></div>
+          </div>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col
+          :span="24"
+          class="right-main"
+        >
+          <router-view @sonFun="indexFun"></router-view>
+        </el-col>
+      </el-row>
+    </el-col>
+  </el-row>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      userName: "",
+      unic: "",
+    };
+  },
+  created() {
+    var statue = sessionStorage.getItem("uname");
+    var token = sessionStorage.getItem("token");
+    var unic = sessionStorage.getItem("unic");
+    if (
+      !statue ||
+      typeof statue == "undefined" ||
+      statue == "" ||
+      statue == "null" ||
+      !token ||
+      typeof token == "undefined" ||
+      token == "" ||
+      token == "null"
+    ) {
+      this.$router.replace("/");
+      return;
+    } else {
+      this.userName = statue;
+      this.unic = unic;
+    }
+  },
+  methods: {
+    // 通过子组件更新昵称
+    indexFun(param) {
+      if (typeof param == "undefined" || !param) {
+        this.unic = sessionStorage.getItem("unic");
+      } else {
+        this.unic = param;
+      }
+    },
+    // 退出登陆
+    logout() {
+      var _this = this;
+      this.$confirm("确认退出?", "提示", {
+        confirmButtonText: "是,退出",
+        cancelButtonText: "否,不退出",
+        type: "warning",
+      })
+        .then((_) => {
+          // console.log(_);
+          sessionStorage.removeItem("uname");
+          sessionStorage.removeItem("token");
+          _this.$router.replace("/");
+        })
+        .catch((_) => {
+          // console.log(_);
+        });
+    },
+  },
+};
+</script>
+
+<style scoped>
+@import url("index.css");
+</style>

+ 91 - 0
src/components/login/login.css

@@ -0,0 +1,91 @@
+html,
+body,
+.container {
+	width: 100vw;
+	height: 100vh;
+	min-width: 1780px;
+	min-height: 900px;
+	background: url(../../../static/images/bg.png) no-repeat;
+	background-size: 100% 100%;
+	margin-bottom: 0;
+	display: flex;
+	flex-direction: column;
+	justify-content: center;
+}
+
+#login_form {
+	display: flex;
+	flex-direction: column;
+	justify-content: center;
+	align-items: center;
+	width: 600px;
+}
+
+#logo {
+	width: 95px;
+	height: 95px;
+	background: url(../../../static/images/logo.png) 0 0 no-repeat;
+	background-size: 95px 95px;
+	opacity: 0;
+}
+
+#title {
+	width: 546px;
+	height: 42px;
+	line-height: 42px;
+	font-size: 38px;
+	font-family: Microsoft YaHei;
+	font-weight: bold;
+	color: #3CADFD;
+	text-align: center;
+	margin-top: 19px;
+	background: linear-gradient(180deg, #4393F8 0%, #535EF0 100%);
+	-webkit-background-clip: text;
+	-webkit-text-fill-color: transparent;
+}
+
+.demo-ruleForm {
+	margin-top: 40px;
+	width: 400px;
+}
+
+.el-form-item {
+	margin-top: 30px;
+}
+
+>>> .el-form-item input {
+	padding-left: 60px;
+	height: 58px;
+	background: #F6F7FB;
+	border-radius: 29px;
+	font-size: 18px;
+}
+
+.el-form-item>>>.el-icon-login-user{
+	margin-left: 22px;
+    background: url(../../../static/images/yonghuming.png) center no-repeat;
+    background-size: contain;
+}
+
+.el-form-item>>>.el-icon-login-pass{
+	margin-left: 22px;
+    background: url(../../../static/images/mima.png) center no-repeat;
+    background-size: contain;
+}
+
+>>>.el-form-item button {
+	margin-top: 32px;
+	width: 400px;
+	height: 58px;
+	background: linear-gradient(180deg, #4393F8, #535EF0);
+	box-shadow: 1px 4px 16px 0px rgba(84, 136, 254, 0.25);
+	border-radius: 29px;
+	font-size: 24px;
+	font-family: Microsoft YaHei-3970(82674968);
+	font-weight: 400;
+	color: #FFFFFF;
+}
+
+>>> .el-form-item__error {
+	padding-left: 60px;
+}

+ 169 - 0
src/components/login/login.vue

@@ -0,0 +1,169 @@
+<template>
+  <div class="container">
+    <el-row>
+      <el-col :span="13">
+        &nbsp;
+      </el-col>
+      <el-col :span="11">
+        <div id="login_form">
+          <div id="logo"></div>
+          <div id="title">旅游大数据上传后台</div>
+          <el-form
+            label-width="0px"
+            :model="ruleForm"
+            status-icon
+            :rules="rules"
+            ref="ruleForm"
+            class="demo-ruleForm"
+          >
+            <el-form-item prop="uname">
+              <el-input
+                ref="zhanghao"
+                placeholder="请输入账号"
+                maxlength="16"
+                v-model="ruleForm.uname"
+                prefix-icon="el-icon-login-user"
+              ></el-input>
+            </el-form-item>
+            <el-form-item prop="upass">
+              <el-input
+                ref="mima"
+                placeholder="请输入密码"
+                maxlength="16"
+                type="password"
+                v-model="ruleForm.upass"
+                prefix-icon="el-icon-login-pass"
+                @keyup.enter.native="submitForm('ruleForm')"
+              >
+              </el-input>
+            </el-form-item>
+            <el-form-item>
+              <el-button
+                type="primary"
+                @click="submitForm('ruleForm')"
+              >登 陆</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    var checkName = (rule, value, callback) => {
+      // console.log(rule, value, callback);
+      if (!value) {
+        return callback(new Error("请输入账号"));
+      }
+      setTimeout(() => {
+        if (value.length < 5) {
+          callback(new Error("账号长度不小于5位"));
+        } else {
+          callback();
+        }
+      }, 30);
+    };
+    var validatePass = (rule, value, callback) => {
+      // console.log(rule, value, callback);
+      if (value === "") {
+        callback(new Error("请输入密码"));
+      }
+      setTimeout(() => {
+        if (value.length < 5) {
+          callback(new Error("密码长度不小于5位"));
+        } else {
+          callback();
+        }
+      }, 30);
+    };
+    return {
+      ruleForm: {
+        uname: "",
+        upass: "",
+      },
+      rules: {
+        uname: [
+          {
+            validator: checkName,
+            trigger: "blur",
+          },
+        ],
+        upass: [
+          {
+            validator: validatePass,
+            trigger: "blur",
+          },
+        ],
+      },
+    };
+  },
+  mounted() {
+    this.$refs["zhanghao"].focus();
+  },
+  methods: {
+    submitForm(formName) {
+      let _this = this;
+      let params = {};
+      var username = String(_this.ruleForm.uname).trim();
+      var userpass = String(_this.ruleForm.upass).trim();
+
+      if (username && userpass) {
+        params.userName = username;
+        params.password = userpass;
+      } else {
+        _this.$message.warning("请输入账号和密码!");
+        if (!username) _this.$refs["zhanghao"].focus();
+        else _this.$refs["mima"].focus();
+        return;
+      }
+
+      _this.$refs[formName].validate((valid) => {
+        _this
+          .$axios({
+            method: "post",
+            url:
+              "/diseaseRight/adminInfo/login?userName=" +
+              username +
+              "&password=" +
+              userpass,
+            headers: {
+              "Content-type": "application/x-www-form-urlencoded;charset=utf-8",
+            },
+          })
+          .then((res) => {
+            // console.log(res.data);
+            if (res.data.success) {
+              // _this.$message.success(res.data.message);
+              sessionStorage.setItem("uname", username);
+              sessionStorage.setItem("userType", res.data.data.userType);
+              sessionStorage.setItem("token", res.data.data.token);
+              // if (typeof(res.data.name) == 'undefined') {
+              // 	sessionStorage.setItem('unic', '未设置昵称')
+              // } else {
+              // 	sessionStorage.setItem('unic', res.data.name)
+              // }
+              _this.$router.replace("/travel/index"); //跳转到首页
+            } else {
+              _this.$message({
+                showClose: true,
+                message: "登陆异常:" + res.data.message,
+                type: "error",
+              });
+            }
+          })
+          .catch((err) => {
+            // console.log(err);
+            _this.$message.error("捕捉异常:" + err);
+          });
+      });
+    },
+  },
+};
+</script>
+
+<style scoped>
+@import url("./login.css");
+</style>

+ 648 - 0
src/components/newsFocus/index.vue

@@ -0,0 +1,648 @@
+<template>
+  <div>
+    <!-- 标题 -->
+    <el-row>
+      <el-col
+        :span="24"
+        class="first-row"
+      >
+        <div class="tag">新闻聚焦</div>
+      </el-col>
+    </el-row>
+
+    <!-- 分割线 -->
+    <hr style="background-color: #CCCCCC;height: 1px;border: 0;">
+    <div style="margin: 32px 0;"></div>
+
+    <!-- 时间选择器和增加按钮 -->
+    <el-row>
+      <el-col :span="8">
+        <el-date-picker
+          v-model="select_datetime"
+          type="daterange"
+          align="center"
+          unlink-panels
+          range-separator="至"
+          :start-placeholder="startTime"
+          :end-placeholder="endTime"
+          @change="dateChange"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          :picker-options="pickerOptions"
+          class="shijian_plus"
+        >
+        </el-date-picker>
+      </el-col>
+      <el-col :span="6">
+        <el-button
+          type="primary"
+          @click="hangdleAddNewsFocus"
+        >添加</el-button>
+      </el-col>
+    </el-row>
+
+    <div style="margin: 20px 0;"></div>
+    <hr style="background-color: #CCCCCC;height: 1px;border: 0;">
+
+    <!-- 表格区域 -->
+    <el-row>
+      <el-col
+        :span="24"
+        class="third-row"
+      >
+        <!-- 表单 -->
+        <el-table
+          :data="tableData"
+          style="width: 100%;font-size: 14px;"
+          highlight-current-row
+          height="450"
+        >
+          <el-table-column
+            prop="title"
+            label="标题"
+            align="center"
+            width="200"
+            show-overflow-tooltip
+          >
+          </el-table-column>
+          <el-table-column
+            prop="publishTime"
+            label="时间"
+            align="center"
+            width="180"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="source"
+            label="来源"
+            align="center"
+            width="200"
+          >
+          </el-table-column>
+
+          <el-table-column
+            prop="content"
+            label="内容"
+            align="center"
+            show-overflow-tooltip
+          >
+          </el-table-column>
+
+          <el-table-column
+            label="图片"
+            align="center"
+            width="180"
+          >
+            <template slot-scope="{row}">
+              <img
+                style="width: 82px; height: 60px"
+                :src="row.image"
+              >
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="操作"
+            align="center"
+            width="180"
+          >
+            <template slot-scope="{ row }">
+              <el-button
+                type="warning"
+                size="mini"
+                @click="amendNewsFocus(row)"
+              >编辑</el-button>
+              <el-button
+                type="danger"
+                size="mini"
+                @click="deleteNewsFocus(row.id)"
+              >删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-col>
+    </el-row>
+
+    <div style="margin: 20px 0;"></div>
+
+    <!-- 分页器 -->
+    <el-row>
+      <div class="pagination_smoke">
+        <el-pagination
+          background
+          layout="prev, pager, next"
+          :total="totalCount"
+          :page-size="pageSize"
+          :current-page.sync="curPage"
+          @current-change="changeCurPage"
+        >
+        </el-pagination>
+      </div>
+
+    </el-row>
+
+    <!-- 新增 新闻聚焦 弹窗 -->
+    <el-dialog
+      title="添加新闻聚焦"
+      :visible.sync="dialogFormVisible"
+      center
+      style="width:90%"
+      top="8vh"
+      :before-close="handleClose"
+    >
+      <el-form
+        :model="form"
+        :rules="rules"
+        ref="form"
+        style="width:80%"
+        label-width="80px"
+      >
+        <el-form-item
+          label="新闻图片"
+          prop="image"
+          ref="headimgUpload"
+        >
+          <el-upload
+            ref="my_upload"
+            action="#"
+            :auto-upload="false"
+            list-type="picture-card"
+            :limit="1"
+            :on-change="getLocalImg"
+            :on-preview="handlePictureCardPreview"
+            :on-exceed="handleExceed"
+            :on-remove="handleRemove"
+          >
+            <i class="el-icon-plus avatar-uploader-icon"></i>
+            <div
+              slot="tip"
+              class="el-upload__tip"
+            >只能上传jpg/jpeg/bmp/png格式,且提示上传图片成功后才能提交添加</div>
+          </el-upload>
+
+          <el-dialog
+            :visible.sync="dialogVisible"
+            append-to-body
+          >
+            <img
+              width="100%"
+              :src="dialogImageUrl"
+            >
+          </el-dialog>
+
+        </el-form-item>
+
+        <el-form-item
+          label="时间"
+          prop="publishTime"
+        >
+          <el-date-picker
+            v-model="form.publishTime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            type="datetime"
+            placeholder="选择日期时间"
+          >
+          </el-date-picker>
+        </el-form-item>
+
+        <el-form-item
+          label="标题"
+          prop="title"
+        >
+          <el-input v-model="form.title"></el-input>
+        </el-form-item>
+
+        <el-form-item
+          label="来源"
+          prop="source"
+        >
+          <el-input v-model="form.source"></el-input>
+        </el-form-item>
+
+        <el-form-item
+          label="内容"
+          prop="content"
+        >
+          <el-input
+            type="textarea"
+            :autosize="{ minRows: 4, maxRows: 6}"
+            v-model="form.content"
+          ></el-input>
+        </el-form-item>
+
+      </el-form>
+      <div slot="footer">
+        <el-button
+          type="primary"
+          @click="addNewsFocus('form')"
+        >确 定</el-button>
+        <el-button @click="dialogFormVisible = false;clearFiles()">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 修改 新闻聚焦 弹窗 -->
+    <el-dialog
+      title="修改新闻聚焦"
+      :visible.sync="dialogFormVisible2"
+      center
+      style="width:90%"
+      top="8vh"
+    >
+      <el-form
+        :model="form"
+        style="width:80%"
+        label-width="80px"
+      >
+        <el-form-item label="新闻图片">
+
+          <el-upload
+            action="#"
+            :auto-upload="false"
+            :show-file-list="false"
+            :on-change="getLocalImg2"
+          >
+            <img
+              v-if="form.image"
+              :src="form.image"
+              class="avatar"
+            >
+            <i
+              v-else
+              class="el-icon-plus avatar-uploader-icon"
+            ></i>
+
+            <div
+              slot="tip"
+              class="el-upload__tip"
+            >只能上传jpg/jpeg/bmp/png格式</div>
+          </el-upload>
+
+        </el-form-item>
+
+        <el-form-item label="时间">
+          <el-date-picker
+            v-model="form.publishTime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            type="datetime"
+            placeholder="选择日期时间"
+          >
+          </el-date-picker>
+        </el-form-item>
+
+        <el-form-item label="标题">
+          <el-input v-model="form.title"></el-input>
+        </el-form-item>
+
+        <el-form-item label="来源">
+          <el-input v-model="form.source"></el-input>
+        </el-form-item>
+
+        <el-form-item label="内容">
+          <el-input
+            type="textarea"
+            :autosize="{ minRows: 4, maxRows: 6}"
+            v-model="form.content"
+          ></el-input>
+        </el-form-item>
+
+      </el-form>
+
+      <div
+        slot="footer"
+        class="dialog-footer"
+      >
+        <el-button
+          type="primary"
+          @click="hangdleAmendNewsFocus"
+        >确 定</el-button>
+        <el-button @click="dialogFormVisible2 = false">取 消</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+export default {
+  name: "",
+  data() {
+    return {
+      select_datetime: [], // 选择的时间范围
+      startTime: "", // 开始时间
+      endTime: "", // 结束时间
+      // 默认时间选择
+      pickerOptions: {
+        shortcuts: [
+          {
+            text: "最近一周",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+          {
+            text: "最近一个月",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+          {
+            text: "最近三个月",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+        ],
+      },
+      tableData: [], // 表格数据
+      curPage: 1, // 当前页
+      pageSize: 4, // 每页记录数
+      totalCount: null, // 总条数
+      dialogVisible: false, // 放大图片弹窗
+      dialogImageUrl: "", // 放大图片数据
+      dialogFormVisible: false, // 增加弹窗
+      dialogFormVisible2: false, // 修改弹窗
+      // 表格数据
+      form: {
+        title: "", // 标题
+        publishTime: "", // 时间
+        source: "", // 来源
+        content: "", // 内容
+        image: "", // 图片
+        imageName: "", // 图片
+      },
+      // 表格验证规则
+      rules: {
+        title: [{ required: true, message: "请输入标题", trigger: "blur" }],
+        publishTime: [
+          { required: true, message: "请选择时间", trigger: "blur" },
+        ],
+        source: [{ required: true, message: "请输入来源", trigger: "blur" }],
+        content: [{ required: true, message: "请输入内容", trigger: "blur" }],
+        image: [{ required: true, message: "请选择图片" }],
+      },
+    };
+  },
+  mounted() {
+    this.getData();
+  },
+  methods: {
+    // 整理参数函数
+    handleCurrentChange(val) {
+      this.curPage = val;
+      this.getData();
+    },
+    // 获取新闻聚焦列表数据
+    async getData() {
+      let params = {
+        curPage: this.curPage,
+        pageSize: this.pageSize,
+        startTime: this.startTime,
+        endTime: this.endTime,
+        // orderField: "startTime",
+        // order: "asc",
+      };
+      let res = await this.$axios({
+        url: "/diseaseRight/newsFocus/list",
+        method: "get",
+        params,
+      });
+      // console.log(res);
+      if (res.data.success) {
+        this.tableData = res.data.data.list;
+        this.totalCount = res.data.data.totalCount;
+      } else {
+        console.log("获取 新闻聚焦列表数据 失败");
+      }
+    },
+    // 上传图片
+    async getLocalImg(file) {
+      let formData = new FormData();
+      formData.append("file", file.raw);
+      let res = await this.$axios({
+        url: "/diseaseRight/file/imageUpload",
+        method: "post",
+        data: formData,
+        headers: {
+          "Admin-Token": sessionStorage.getItem("token"),
+        },
+      });
+      // console.log(res);
+      if (res.data.success) {
+        // 响应式添加image的值
+        this.$set(this.form, "image", res.data.data.imageName);
+        this.$message.success("图片上传成功!");
+        //等待照片上传完成清除验证提示
+        this.$nextTick(() => {
+          this.$refs["headimgUpload"].clearValidate();
+        });
+        // console.log(this.form.image);
+      } else {
+        this.$message.error("图片上传失败!");
+      }
+    },
+    async getLocalImg2(file) {
+      let formData = new FormData();
+      formData.append("file", file.raw);
+      let res = await this.$axios({
+        url: "/diseaseRight/file/imageUpload",
+        method: "post",
+        data: formData,
+        headers: {
+          "Admin-Token": sessionStorage.getItem("token"),
+        },
+      });
+      // console.log(res);
+      if (res.data.success) {
+        this.form.image = res.data.data.showUrl;
+      } else {
+        console.log("上传图片失败");
+      }
+    },
+    hangdleAddNewsFocus() {
+      this.dialogFormVisible = true;
+      this.form = {};
+      this.$nextTick(() => {
+        this.clearFiles();
+      });
+    },
+    // 添加新闻聚焦
+    addNewsFocus(formName) {
+      this.$refs[formName].validate(async (valid) => {
+        if (valid) {
+          this.dialogFormVisible = false;
+          let res = await this.$axios({
+            method: "post",
+            url: "/diseaseRight/newsFocus/save",
+            headers: {
+              "Admin-Token": sessionStorage.getItem("token"),
+            },
+            data: this.form,
+          });
+          // console.log(res);
+          if (res.data.success) {
+            this.handleCurrentChange(1);
+            this.$message.success("添加成功!");
+            this.clearFiles();
+          } else {
+            this.$message.error("添加失败!");
+          }
+        } else {
+          console.log("提交失败!!");
+          return false;
+        }
+      });
+    },
+    // 修改新闻聚焦
+    amendNewsFocus(row) {
+      // console.log(row);
+      this.form = { ...row };
+      this.dialogFormVisible2 = true;
+    },
+    // 修改新闻聚焦请求
+    async hangdleAmendNewsFocus() {
+      this.dialogFormVisible2 = false;
+      this.form.image = this.form.imageName;
+      let res = await this.$axios({
+        method: "put",
+        url: "/diseaseRight/newsFocus/update",
+        headers: {
+          "Admin-Token": sessionStorage.getItem("token"),
+        },
+        data: this.form,
+      });
+      // console.log(res);
+      if (res.data.success) {
+        this.handleCurrentChange(this.curPage);
+        this.$message.success("修改成功!");
+      } else {
+        this.$message.error("修改失败!");
+      }
+    },
+    // 删除新闻聚焦
+    deleteNewsFocus(id) {
+      this.$confirm("确定删除吗?", "提示", {
+        cancelButtonText: "取消",
+        confirmButtonText: "确定",
+        type: "warning",
+      })
+        .then(async () => {
+          let res = await this.$axios({
+            method: "delete",
+            url: "/diseaseRight/newsFocus/delete",
+            headers: {
+              "Admin-Token": sessionStorage.getItem("token"),
+            },
+            data: [id],
+          });
+          // console.log(res);
+          if (res.data.success) {
+            this.$message.success("删除成功");
+            let totalPage = Math.ceil((this.totalCount - 1) / this.pageSize);
+            let currentPage =
+              this.curPage > totalPage ? totalPage : this.curPage;
+            this.curPage = currentPage < 1 ? 1 : currentPage;
+            this.handleCurrentChange(this.curPage);
+          } else {
+            this.$message.error("删除失败!");
+          }
+        })
+        .catch(() => {
+          this.$message.info("已取消");
+        });
+    },
+    // 改变时间函数
+    dateChange(val) {
+      if (val) {
+        this.startTime = val[0];
+        this.endTime = val[1];
+        this.handleCurrentChange(1);
+      } else {
+        this.startTime = "";
+        this.endTime = "";
+        this.handleCurrentChange(1);
+      }
+    },
+    // 换页逻辑
+    changeCurPage(val) {
+      // console.log(`当前页: ${val}`);
+      this.handleCurrentChange(val);
+    },
+    // 点击文件列表中已上传的文件时的钩子 放大图片
+    handlePictureCardPreview(file) {
+      this.dialogImageUrl = file.url;
+      this.dialogVisible = true;
+    },
+    // 文件超出个数限制时的钩子
+    handleExceed() {
+      this.$message.warning(`只能同时上传一张照片`);
+    },
+    // 文件列表移除文件时的钩子
+    handleRemove() {
+      this.form.image = "";
+    },
+    // 清空已上传的文件列表
+    clearFiles() {
+      this.$refs.my_upload.clearFiles();
+    },
+    // Dialog关闭前的回调
+    handleClose(done) {
+      this.clearFiles();
+      done();
+    },
+  },
+};
+</script>
+
+<style scoped>
+.first-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  height: 50px;
+}
+.tag {
+  width: 108px;
+  height: 40px;
+  font-size: 24px;
+  font-family: Microsoft YaHei-3970(82674968);
+  font-weight: bold;
+  color: #000000;
+  line-height: 54px;
+}
+.shijian_plus.el-date-editor--daterange {
+  width: 250px;
+}
+.third-row {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-top: 0;
+}
+.pagination_smoke {
+  text-align: center;
+}
+
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 120px;
+  height: 120px;
+  line-height: 120px;
+  text-align: center;
+  border-radius: 6px;
+  border: 1px dashed #ccc;
+}
+.avatar {
+  width: 120px;
+  height: 120px;
+  display: block;
+}
+</style>

+ 556 - 0
src/components/peopleCoefficient/index.vue

@@ -0,0 +1,556 @@
+<template>
+  <div>
+
+    <!-- 标题 -->
+    <el-row>
+      <el-col
+        :span="24"
+        class="first-row"
+      >
+        <div class="tag">人次系数</div>
+      </el-col>
+    </el-row>
+
+    <!-- 分割线 -->
+    <hr style="background-color: #CCCCCC;height: 1px;border: 0;">
+
+    <!-- 主体内容 -->
+    <el-tabs>
+      <!-- 基础系数区域 -->
+      <el-tab-pane label="基础系数">
+        <el-row>
+          <el-col
+            v-for="item in list"
+            :key="item.id"
+            :span="9"
+            style="marginTop: 32px"
+          >
+            <el-col :span="8">
+              <span>{{item.id-1}}、{{item.xs_name}}</span>
+            </el-col>
+
+            <el-input
+              class="input-new-tag"
+              v-if="item.show"
+              v-model="inputValue"
+              v-fo
+              size="small"
+              @blur="handleInputConfirm(item)"
+            >
+            </el-input>
+            <el-button
+              v-else
+              class="button-new-tag"
+              size="small"
+              @click="showInput(item)"
+            >{{item.xs2}}</el-button>
+
+          </el-col>
+        </el-row>
+      </el-tab-pane>
+
+      <!-- 过夜游客区域 -->
+      <el-tab-pane label="过夜游客各乡镇基数">
+        <el-row>
+
+          <el-col
+            :span="8"
+            style="marginTop: 32px;lineHeight:100%"
+          >
+            <el-col :span="12">
+              <span>1、双溪镇</span>
+            </el-col>
+
+            <el-input
+              class="input-new-tag"
+              v-if="show"
+              v-model="inputValue_place"
+              v-fo
+              size="small"
+              @blur="handleInputConfirm_place(1)"
+            >
+            </el-input>
+            <el-button
+              v-else
+              class="button-new-tag"
+              size="small"
+              @click="showInput_place(1)"
+            >{{placeInfo.xs}}</el-button>
+          </el-col>
+
+          <el-col
+            :span="8"
+            style="marginTop: 32px;lineHeight:100%"
+          >
+            <el-col :span="12">
+              <span>2、香田乡</span>
+            </el-col>
+
+            <el-input
+              class="input-new-tag"
+              v-if="show2"
+              v-model="inputValue_place"
+              v-fo
+              size="small"
+              @blur="handleInputConfirm_place(2)"
+            >
+            </el-input>
+            <el-button
+              v-else
+              class="button-new-tag"
+              size="small"
+              @click="showInput_place(2)"
+            >{{placeInfo.xs2}}</el-button>
+          </el-col>
+
+          <el-col
+            :span="8"
+            style="marginTop: 32px;lineHeight:100%"
+          >
+            <el-col :span="12">
+              <span>3、宝峰镇</span>
+            </el-col>
+
+            <el-input
+              class="input-new-tag"
+              v-if="show3"
+              v-model="inputValue_place"
+              v-fo
+              size="small"
+              @blur="handleInputConfirm_place(3)"
+            >
+            </el-input>
+            <el-button
+              v-else
+              class="button-new-tag"
+              size="small"
+              @click="showInput_place(3)"
+            >{{placeInfo.xs3}}</el-button>
+          </el-col>
+
+          <el-col
+            :span="8"
+            style="marginTop: 32px;lineHeight:100%"
+          >
+            <el-col :span="12">
+              <span>4、高湖镇</span>
+            </el-col>
+
+            <el-input
+              class="input-new-tag"
+              v-if="show4"
+              v-model="inputValue_place"
+              v-fo
+              size="small"
+              @blur="handleInputConfirm_place(4)"
+            >
+            </el-input>
+            <el-button
+              v-else
+              class="button-new-tag"
+              size="small"
+              @click="showInput_place(4)"
+            >{{placeInfo.xs4}}</el-button>
+          </el-col>
+
+          <el-col
+            :span="8"
+            style="marginTop: 32px;lineHeight:100%"
+          >
+            <el-col :span="12">
+              <span>5、三爪仑乡</span>
+            </el-col>
+
+            <el-input
+              class="input-new-tag"
+              v-if="show5"
+              v-model="inputValue_place"
+              v-fo
+              size="small"
+              @blur="handleInputConfirm_place(5)"
+            >
+            </el-input>
+            <el-button
+              v-else
+              class="button-new-tag"
+              size="small"
+              @click="showInput_place(5)"
+            >{{placeInfo.xs5}}</el-button>
+          </el-col>
+
+          <el-col
+            :span="8"
+            style="marginTop: 32px;lineHeight:100%"
+          >
+            <el-col :span="12">
+              <span>6、中源乡</span>
+            </el-col>
+
+            <el-input
+              class="input-new-tag"
+              v-if="show6"
+              v-model="inputValue_place"
+              v-fo
+              size="small"
+              @blur="handleInputConfirm_place(6)"
+            >
+            </el-input>
+            <el-button
+              v-else
+              class="button-new-tag"
+              size="small"
+              @click="showInput_place(6)"
+            >{{placeInfo.xs6}}</el-button>
+          </el-col>
+
+          <el-col
+            :span="8"
+            style="marginTop: 32px;lineHeight:100%"
+          >
+            <el-col :span="12">
+              <span>7、水口乡</span>
+            </el-col>
+
+            <el-input
+              class="input-new-tag"
+              v-if="show7"
+              v-model="inputValue_place"
+              v-fo
+              size="small"
+              @blur="handleInputConfirm_place(7)"
+            >
+            </el-input>
+            <el-button
+              v-else
+              class="button-new-tag"
+              size="small"
+              @click="showInput_place(7)"
+            >{{placeInfo.xs7}}</el-button>
+          </el-col>
+
+          <el-col
+            :span="8"
+            style="marginTop: 32px;lineHeight:100%"
+          >
+            <el-col :span="12">
+              <span>8、雷公尖乡</span>
+            </el-col>
+
+            <el-input
+              class="input-new-tag"
+              v-if="show8"
+              v-model="inputValue_place"
+              v-fo
+              size="small"
+              @blur="handleInputConfirm_place(8)"
+            >
+            </el-input>
+            <el-button
+              v-else
+              class="button-new-tag"
+              size="small"
+              @click="showInput_place(8)"
+            >{{placeInfo.xs8}}</el-button>
+          </el-col>
+
+          <el-col
+            :span="8"
+            style="marginTop: 32px;lineHeight:100%"
+          >
+            <el-col :span="12">
+              <span>9、仁首镇</span>
+            </el-col>
+
+            <el-input
+              class="input-new-tag"
+              v-if="show9"
+              v-model="inputValue_place"
+              v-fo
+              size="small"
+              @blur="handleInputConfirm_place(9)"
+            >
+            </el-input>
+            <el-button
+              v-else
+              class="button-new-tag"
+              size="small"
+              @click="showInput_place(9)"
+            >{{placeInfo.xs9}}</el-button>
+          </el-col>
+
+          <el-col
+            :span="8"
+            style="marginTop: 32px;lineHeight:100%"
+          >
+            <el-col :span="12">
+              <span>10、璪都镇</span>
+            </el-col>
+
+            <el-input
+              class="input-new-tag"
+              v-if="show10"
+              v-model="inputValue_place"
+              v-fo
+              size="small"
+              @blur="handleInputConfirm_place(10)"
+            >
+            </el-input>
+            <el-button
+              v-else
+              class="button-new-tag"
+              size="small"
+              @click="showInput_place(10)"
+            >{{placeInfo.xs10}}</el-button>
+          </el-col>
+
+          <el-col
+            :span="8"
+            style="marginTop: 32px;lineHeight:100%"
+          >
+            <el-col :span="12">
+              <span>11、官庄镇</span>
+            </el-col>
+
+            <el-input
+              class="input-new-tag"
+              v-if="show11"
+              v-model="inputValue_place"
+              v-fo
+              size="small"
+              @blur="handleInputConfirm_place(11)"
+            >
+            </el-input>
+            <el-button
+              v-else
+              class="button-new-tag"
+              size="small"
+              @click="showInput_place(11)"
+            >{{placeInfo.xs11}}</el-button>
+          </el-col>
+
+        </el-row>
+
+      </el-tab-pane>
+    </el-tabs>
+
+  </div>
+</template>
+
+<script>
+export default {
+  name: "",
+  data() {
+    return {
+      list: [], //基础系数数据
+      inputValue: "", //基础系数输入框绑定数据
+      form: {}, //修改基础系数请求参数
+
+      placeInfo: {}, //过夜游客基数数据
+      inputValue_place: "", //过夜游客基数输入框绑定数据
+
+      show: false,
+      show2: false,
+      show3: false,
+      show4: false,
+      show5: false,
+      show6: false,
+      show7: false,
+      show8: false,
+      show9: false,
+      show10: false,
+      show11: false,
+    };
+  },
+  mounted() {
+    this.getData();
+    //  this.getData_place();
+  },
+  methods: {
+    // 获取 基础系数 数据
+    async getData() {
+      let res = await this.$axios.post("/bigData2/tourqueryTourx.action");
+      // console.log(res);
+      if (res.status == 200) {
+        res.data.data.forEach((element, index) => {
+          element.show = false;
+          return element;
+        });
+        let newList = [];
+        let newList2 = [];
+        res.data.data.forEach((element, index) => {
+          if (index !== 0) {
+            newList.push(element);
+          } else {
+            newList2.push(element);
+          }
+        });
+        this.list = newList;
+        this.placeInfo = newList2[0];
+        // console.log(this.list);
+        // console.log(this.placeInfo);
+      } else {
+        console.log("获取 基础系数数据 失败");
+      }
+    },
+    // 修改 基础系数 数据
+    async editData() {
+      let res = await this.$axios({
+        url: "/bigData2/tourupdateTx.action",
+        method: "post",
+        params: this.form,
+        // headers: {
+        //   "Admin-Token": sessionStorage.getItem("token"),
+        // },
+      });
+      // console.log(res);
+      if (res.data.statusCode == 200) {
+        this.$message({
+          showClose: true,
+          message: "修改成功",
+          type: "success",
+        });
+      } else {
+        this.$message({
+          showClose: true,
+          message: "修改失败",
+          type: "error",
+        });
+      }
+      this.getData();
+    },
+    // 基础系数区域 失去焦点 切换回按钮 并更新数据
+    handleInputConfirm(i) {
+      i.show = false;
+      i.xs2 = this.inputValue;
+      this.form = { ...i };
+      this.editData();
+      this.inputValue = "";
+    },
+    // 基础系数区域 点击按钮 切换输入框 并聚焦
+    showInput(i) {
+      i.show = true;
+    },
+
+    // 修改 过夜游客基数 数据
+    async editData2() {
+      let res = await this.$axios({
+        url: "/bigData2/tourupdateTx.action",
+        method: "post",
+        params: this.placeInfo,
+        // headers: {
+        //   "Admin-Token": sessionStorage.getItem("token"),
+        // },
+      });
+      // console.log(res);
+      if (res.data.statusCode == 200) {
+        this.$message({
+          showClose: true,
+          message: "修改成功",
+          type: "success",
+        });
+      } else {
+        this.$message({
+          showClose: true,
+          message: "修改失败",
+          type: "error",
+        });
+      }
+      this.getData();
+    },
+    // 过夜游客区域 失去焦点 切换回按钮 并更新数据
+    handleInputConfirm_place(i) {
+      if (i == 1) {
+        this.placeInfo.xs = this.inputValue_place;
+        this.show = false;
+      } else if (i == 2) {
+        this.placeInfo.xs2 = this.inputValue_place;
+        this.show2 = false;
+      } else if (i == 3) {
+        this.placeInfo.xs3 = this.inputValue_place;
+        this.show3 = false;
+      } else if (i == 4) {
+        this.placeInfo.xs4 = this.inputValue_place;
+        this.show4 = false;
+      } else if (i == 5) {
+        this.placeInfo.xs5 = this.inputValue_place;
+        this.show5 = false;
+      } else if (i == 6) {
+        this.placeInfo.xs6 = this.inputValue_place;
+        this.show6 = false;
+      } else if (i == 7) {
+        this.placeInfo.xs7 = this.inputValue_place;
+        this.show7 = false;
+      } else if (i == 8) {
+        this.placeInfo.xs8 = this.inputValue_place;
+        this.show8 = false;
+      } else if (i == 9) {
+        this.placeInfo.xs9 = this.inputValue_place;
+        this.show9 = false;
+      } else if (i == 10) {
+        this.placeInfo.xs10 = this.inputValue_place;
+        this.show10 = false;
+      } else {
+        this.placeInfo.xs11 = this.inputValue_place;
+        this.show11 = false;
+      }
+      this.editData2();
+      this.inputValue_place = "";
+    },
+    // 过夜游客区域 点击按钮 切换输入框 并聚焦
+    showInput_place(i) {
+      if (i == 1) {
+        this.show = true;
+      } else if (i == 2) {
+        this.show2 = true;
+      } else if (i == 3) {
+        this.show3 = true;
+      } else if (i == 4) {
+        this.show4 = true;
+      } else if (i == 5) {
+        this.show5 = true;
+      } else if (i == 6) {
+        this.show6 = true;
+      } else if (i == 7) {
+        this.show7 = true;
+      } else if (i == 8) {
+        this.show8 = true;
+      } else if (i == 9) {
+        this.show9 = true;
+      } else if (i == 10) {
+        this.show10 = true;
+      } else {
+        this.show11 = true;
+      }
+    },
+  },
+};
+</script>
+
+<style scoped>
+.first-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  height: 50px;
+}
+.tag {
+  width: 108px;
+  height: 40px;
+  font-size: 24px;
+  font-family: Microsoft YaHei-3970(82674968);
+  font-weight: bold;
+  color: #000000;
+  line-height: 54px;
+}
+.input-new-tag {
+  margin-right: 10px;
+  width: 90px;
+  vertical-align: middle;
+}
+.button-new-tag {
+  margin-right: 10px;
+  width: 90px;
+  height: 32px;
+  vertical-align: middle;
+}
+</style>

+ 845 - 0
src/components/serve/index.vue

@@ -0,0 +1,845 @@
+<template>
+  <div>
+    <!-- 标题 -->
+    <el-row class="first-row">
+      <div class="tag">智慧服务</div>
+    </el-row>
+
+    <!-- 分割线 -->
+    <hr style="background-color: #CCCCCC;height: 1px;border: 0;">
+
+    <el-tabs>
+      <!-- 智慧厕所区域 -->
+      <el-tab-pane label="智慧厕所">
+        <!-- 增加按钮和搜索框 -->
+        <el-row style="marginTop:10px">
+          <el-col :span="3">
+            <el-button
+              type="primary"
+              icon="el-icon-plus"
+              @click="handleAdd"
+            >添加厕所</el-button>
+          </el-col>
+          <el-col
+            :span="2"
+            style="fontSize:15px;marginTop:10px"
+          >筛选条件:
+          </el-col>
+          <el-col
+            :span="4"
+            style="marginLeft:-40px"
+          >
+            <el-input
+              placeholder="请输入编号或者厕所名称"
+              suffix-icon="el-icon-search"
+              clearable
+              v-model="keyword"
+              @change="getData()"
+            >
+            </el-input>
+          </el-col>
+        </el-row>
+        <div style="margin: 20px 0;"></div>
+        <hr style="background-color: #CCCCCC;height: 1px;border: 0;">
+        <!-- 表格区域 -->
+        <el-row>
+          <el-table
+            :data="tableData"
+            highlight-current-row
+            height="450"
+            v-loading="loading"
+            element-loading-text="加载中"
+            element-loading-spinner="el-icon-loading"
+          >
+            <el-table-column
+              prop="itemNo"
+              label="项目编号"
+              align="center"
+              width="100"
+            >
+            </el-table-column>
+            <el-table-column
+              prop="name"
+              label="厕所名称"
+              align="center"
+              width="180"
+            >
+            </el-table-column>
+            <el-table-column
+              prop="addrDesc"
+              label="地址"
+              align="center"
+              width="190"
+            >
+            </el-table-column>
+
+            <el-table-column
+              prop="area"
+              label="厕所面积/㎡"
+              align="center"
+            >
+            </el-table-column>
+            <el-table-column
+              prop="level"
+              label="建设等级"
+              align="center"
+            >
+            </el-table-column>
+            <el-table-column
+              prop="numOfMan"
+              label="男厕位/个"
+              align="center"
+            >
+            </el-table-column>
+            <el-table-column
+              prop="numOfWoman"
+              label="女厕所/个"
+              align="center"
+            >
+            </el-table-column>
+            <el-table-column
+              prop="numOfBarrierFree"
+              label="无障碍厕位/个"
+              align="center"
+            >
+            </el-table-column>
+            <el-table-column
+              prop="numOfThird"
+              label="第三卫生间/个"
+              align="center"
+            >
+            </el-table-column>
+            <el-table-column
+              prop="numOfCommon"
+              label="男女通用厕位/个"
+              align="center"
+              width="130"
+            >
+            </el-table-column>
+
+            <el-table-column
+              label="操作"
+              align="center"
+              width="150"
+            >
+              <template slot-scope="{ row }">
+                <el-button
+                  type="warning"
+                  size="mini"
+                  @click="editToilet(row)"
+                >编辑</el-button>
+                <el-button
+                  type="danger"
+                  size="mini"
+                  @click="deleteToilet(row)"
+                >删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-row>
+        <div style="margin: 20px 0;"></div>
+        <!-- 分页器 -->
+        <el-row>
+          <div class="pagination_smoke">
+            <el-pagination
+              background
+              layout="total,prev, pager, next"
+              :total="totalCount"
+              :page-size="pageSize"
+              :current-page.sync="curPage"
+              @current-change="getData"
+            >
+            </el-pagination>
+          </div>
+
+        </el-row>
+      </el-tab-pane>
+
+      <!-- 智慧停车区域 -->
+      <el-tab-pane label="智慧停车">
+        <!-- 增加按钮和搜索框 -->
+        <el-row style="marginTop:10px">
+          <el-col :span="3">
+            <el-button
+              type="primary"
+              icon="el-icon-plus"
+              @click="handleAdd2"
+            >添加停车场</el-button>
+          </el-col>
+          <el-col
+            :span="2"
+            style="fontSize:15px;marginTop:10px"
+          >筛选条件:
+          </el-col>
+          <el-col
+            :span="4"
+            style="marginLeft:-40px"
+          >
+            <el-input
+              placeholder="请输入名称"
+              suffix-icon="el-icon-search"
+              clearable
+              v-model="keyword2"
+              @change="getData2()"
+            >
+            </el-input>
+          </el-col>
+        </el-row>
+
+        <div style="margin: 20px 0;"></div>
+        <hr style="background-color: #CCCCCC;height: 1px;border: 0;">
+
+        <!-- 表格区域 -->
+        <el-row>
+          <el-table
+            :data="tableData2"
+            highlight-current-row
+            height="450"
+            v-loading="loading"
+            element-loading-text="加载中"
+            element-loading-spinner="el-icon-loading"
+          >
+            <el-table-column
+              prop="name"
+              label="名称"
+              align="center"
+            >
+            </el-table-column>
+            <el-table-column
+              prop="addrDesc"
+              label="地址"
+              align="center"
+            >
+            </el-table-column>
+            <el-table-column
+              prop="openTime"
+              label="营业时间"
+              align="center"
+              width="200"
+            >
+            </el-table-column>
+
+            <el-table-column
+              prop="capacity"
+              label="容量/辆"
+              align="center"
+              width="150"
+            >
+            </el-table-column>
+
+            <el-table-column
+              label="操作"
+              align="center"
+            >
+              <template slot-scope="{ row }">
+                <el-button
+                  type="warning"
+                  size="mini"
+                  @click="editPark(row)"
+                >编辑</el-button>
+                <el-button
+                  type="danger"
+                  size="mini"
+                  @click="deletePark(row)"
+                >删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-row>
+
+        <div style="margin: 20px 0;"></div>
+
+        <!-- 分页器 -->
+        <el-row>
+          <div class="pagination_smoke">
+            <el-pagination
+              background
+              layout="total,prev, pager, next"
+              :total="totalCount2"
+              :page-size="pageSize2"
+              :current-page.sync="curPage2"
+              @current-change="getData2"
+            >
+            </el-pagination>
+          </div>
+
+        </el-row>
+
+      </el-tab-pane>
+    </el-tabs>
+
+    <!-- 新增或编辑 厕所 弹窗 -->
+    <el-dialog
+      :title="title"
+      :visible.sync="dialogFormVisible"
+      :close-on-click-modal="false"
+      center
+      top="3vh"
+    >
+      <el-form
+        :model="form"
+        :rules="rules"
+        ref="form"
+        style="width:80%"
+        label-width="130px"
+      >
+        <el-form-item
+          label="项目编号"
+          prop="itemNo"
+        >
+          <el-input
+            v-model="form.itemNo"
+            placeholder="请输入项目编号"
+          ></el-input>
+        </el-form-item>
+        <el-form-item
+          label="厕所名称"
+          prop="name"
+        >
+          <el-input
+            v-model="form.name"
+            placeholder="请输入厕所名称"
+          ></el-input>
+        </el-form-item>
+        <el-form-item
+          label="地址"
+          prop="addrDesc"
+        >
+          <el-input
+            v-model="form.addrDesc"
+            placeholder="请输入地址"
+          ></el-input>
+        </el-form-item>
+        <el-form-item
+          label="厕所面积/㎡"
+          prop="area"
+        >
+          <el-input
+            v-model="form.area"
+            placeholder="请输入厕所面积"
+          ></el-input>
+        </el-form-item>
+        <el-form-item
+          label="建设等级"
+          prop="level"
+        >
+          <el-input
+            v-model="form.level"
+            placeholder="请输入建设等级"
+          ></el-input>
+        </el-form-item>
+        <el-form-item
+          label="男厕位/个"
+          prop="numOfMan"
+        >
+          <el-input
+            v-model="form.numOfMan"
+            placeholder="请输入数量"
+          ></el-input>
+        </el-form-item>
+        <el-form-item
+          label="女厕位/个"
+          prop="numOfWoman"
+        >
+          <el-input
+            v-model="form.numOfWoman"
+            placeholder="请输入数量"
+          ></el-input>
+        </el-form-item>
+        <el-form-item
+          label="无障碍厕位/个"
+          prop="numOfBarrierFree"
+        >
+          <el-input
+            v-model="form.numOfBarrierFree"
+            placeholder="请输入数量"
+          ></el-input>
+        </el-form-item>
+        <el-form-item
+          label="第三卫生间/个"
+          prop="numOfThird"
+        >
+          <el-input
+            v-model="form.numOfThird"
+            placeholder="请输入数量"
+          ></el-input>
+        </el-form-item>
+        <el-form-item
+          label="男女通用厕位/个"
+          prop="numOfCommon"
+        >
+          <el-input
+            v-model="form.numOfCommon"
+            placeholder="请输入数量"
+          ></el-input>
+        </el-form-item>
+
+        <el-form-item
+          label="经纬度"
+          prop="longitudeAndLatitude"
+        >
+          <el-input
+            v-model="form.longitudeAndLatitude"
+            placeholder="请输入经纬度"
+          ></el-input>
+        </el-form-item>
+
+      </el-form>
+      <div
+        slot="footer"
+        class="dialog-footer"
+      >
+        <el-button
+          type="primary"
+          @click="handleAddOrUpdata('form')"
+        >确 定</el-button>
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 新增或编辑 停车 弹窗 -->
+    <el-dialog
+      :title="title2"
+      :visible.sync="dialogFormVisible2"
+      :close-on-click-modal="false"
+      center
+      style="width:90%"
+    >
+      <el-form
+        :model="form2"
+        :rules="rules2"
+        ref="form2"
+        style="width:80%"
+        label-width="80px"
+      >
+        <el-form-item
+          label="名称"
+          prop="name"
+        >
+          <el-input
+            v-model="form2.name"
+            placeholder="请输入名称"
+          ></el-input>
+        </el-form-item>
+        <el-form-item
+          label="地址"
+          prop="addrDesc"
+        >
+          <el-input
+            v-model="form2.addrDesc"
+            placeholder="请输入地址"
+          ></el-input>
+        </el-form-item>
+        <el-form-item
+          label="时间"
+          prop="openTime"
+        >
+          <el-input
+            v-model="form2.openTime"
+            placeholder="请输入营业时间"
+          ></el-input>
+        </el-form-item>
+        <el-form-item
+          label="容量/辆"
+          prop="capacity"
+        >
+          <el-input
+            v-model="form2.capacity"
+            placeholder="请输入容量"
+          ></el-input>
+        </el-form-item>
+
+        <el-form-item
+          label="经纬度"
+          prop="longitudeAndLatitude"
+        >
+          <el-input
+            v-model="form2.longitudeAndLatitude"
+            placeholder="请输入经纬度"
+          ></el-input>
+        </el-form-item>
+
+      </el-form>
+      <div
+        slot="footer"
+        class="dialog-footer"
+      >
+        <el-button
+          type="primary"
+          @click="handleAddOrUpdata2('form2')"
+        >确 定</el-button>
+        <el-button @click="dialogFormVisible2 = false">取 消</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+export default {
+  name: "Serve",
+  data() {
+    return {
+      keyword: "", //智慧厕所搜索框绑定值
+      tableData: [], //智慧厕所列表数据
+      loading: false, //加载效果
+      curPage: 1, // 智慧厕所当前页
+      pageSize: 5, // 智慧厕所每页记录数
+      totalCount: null, // 智慧厕所总条数
+      dialogFormVisible: false, //智慧厕所弹窗控制
+      //智慧厕所弹窗表格绑定数据
+      form: {
+        itemNo: "",
+        name: "",
+        addrDesc: "",
+        area: "",
+        level: "",
+        numOfMan: "",
+        numOfWoman: "",
+        numOfBarrierFree: "",
+        numOfThird: "",
+        numOfCommon: "",
+        longitudeAndLatitude: "",
+      },
+      //智慧厕所弹窗表格验证规则
+      rules: {
+        itemNo: [
+          { required: true, message: "请输入项目编号", trigger: "blur" },
+        ],
+        name: [{ required: true, message: "请输入厕所名称", trigger: "blur" }],
+        addrDesc: [{ required: true, message: "请输入地址", trigger: "blur" }],
+        area: [{ required: true, message: "请输入厕所面积", trigger: "blur" }],
+        level: [{ required: true, message: "请输入建设等级", trigger: "blur" }],
+        numOfMan: [{ required: true, message: "请输入数量", trigger: "blur" }],
+        numOfWoman: [
+          { required: true, message: "请输入数量", trigger: "blur" },
+        ],
+        numOfBarrierFree: [
+          { required: true, message: "请输入数量", trigger: "blur" },
+        ],
+        numOfThird: [
+          { required: true, message: "请输入数量", trigger: "blur" },
+        ],
+        numOfCommon: [
+          { required: true, message: "请输入数量", trigger: "blur" },
+        ],
+        longitudeAndLatitude: [
+          { required: true, message: "请输入经纬度", trigger: "blur" },
+        ],
+      },
+      title: "", //智慧厕所弹窗标题
+
+      keyword2: "", //智慧停车搜索框绑定值
+      tableData2: [], //智慧停车列表数据
+      curPage2: 1, // 智慧停车当前页
+      pageSize2: 7, // 智慧停车每页记录数
+      totalCount2: null, // 智慧停车总条数
+      dialogFormVisible2: false, //智慧停车弹窗控制
+      //智慧停车弹窗表格绑定数据
+      form2: {
+        name: "",
+        addrDesc: "",
+        openTime: "",
+        capacity: "",
+        longitudeAndLatitude: "",
+      },
+      //智慧停车弹窗表格验证规则
+      rules2: {
+        name: [{ required: true, message: "请输入名称", trigger: "blur" }],
+        addrDesc: [{ required: true, message: "请输入地址", trigger: "blur" }],
+        openTime: [
+          { required: true, message: "请输入营业时间", trigger: "blur" },
+        ],
+        capacity: [{ required: true, message: "请输入容量", trigger: "blur" }],
+        longitudeAndLatitude: [
+          { required: true, message: "请输入经纬度", trigger: "blur" },
+        ],
+      },
+      title2: "", //智慧停车弹窗标题
+    };
+  },
+  mounted() {
+    this.getData();
+    this.getData2();
+  },
+  methods: {
+    //获取智慧厕所列表数据
+    async getData(val = 1) {
+      this.loading = true;
+      this.curPage = val;
+      let params = {
+        curPage: this.curPage,
+        pageSize: this.pageSize,
+        keyword: this.keyword,
+      };
+      let res = await this.$axios({
+        url: "/diseaseRight/toilet/page",
+        method: "get",
+        params,
+      });
+      //   console.log(res);
+      if (res.data.success) {
+        this.tableData = res.data.data.list;
+        this.totalCount = res.data.data.totalCount;
+      } else {
+        console.log("获取 智慧厕所列表数据 失败");
+      }
+      this.loading = false;
+    },
+    // 添加厕所按钮回调
+    handleAdd() {
+      this.dialogFormVisible = true;
+      this.title = "添加";
+      this.$nextTick(() => {
+        this.$refs.form.resetFields();
+        this.form = {
+          itemNo: "",
+          name: "",
+          addrDesc: "",
+          area: "",
+          level: "",
+          numOfMan: "",
+          numOfWoman: "",
+          numOfBarrierFree: "",
+          numOfThird: "",
+          numOfCommon: "",
+          longitudeAndLatitude: "",
+        };
+      });
+    },
+    // 编辑厕所按钮回调
+    editToilet(row) {
+      this.dialogFormVisible = true;
+      this.title = "编辑";
+      this.$nextTick(() => {
+        this.$refs.form.resetFields();
+        this.form = { ...row };
+      });
+    },
+    // 添加或编辑 厕所 请求
+    handleAddOrUpdata(formName) {
+      this.$refs[formName].validate(async (valid) => {
+        if (valid) {
+          this.dialogFormVisible = false;
+          if (this.form.id) {
+            // 编辑请求
+            let res = await this.$axios({
+              method: "put",
+              url: "/diseaseRight/toilet/update",
+              headers: {
+                "Admin-Token": sessionStorage.getItem("token"),
+              },
+              data: this.form,
+            });
+            // console.log(res);
+            if (res.data.success) {
+              this.getData(this.curPage);
+              this.$message.success("编辑成功!");
+            } else {
+              this.$message.error(res.data.message);
+            }
+          } else {
+            // 添加请求
+            let res = await this.$axios({
+              method: "post",
+              url: "/diseaseRight/toilet/save",
+              headers: {
+                "Admin-Token": sessionStorage.getItem("token"),
+              },
+              data: this.form,
+            });
+            // console.log(res);
+            if (res.data.success) {
+              this.getData(1);
+              this.$message.success("添加成功!");
+            } else {
+              this.$message.error(res.data.message);
+            }
+          }
+        } else {
+          console.log("提交失败!!");
+          return false;
+        }
+      });
+    },
+    // 删除厕所按钮回调
+    deleteToilet(row) {
+      this.$confirm("确定删除吗?", "提示", {
+        cancelButtonText: "取消",
+        confirmButtonText: "确定",
+        type: "warning",
+      })
+        .then(async () => {
+          let res = await this.$axios({
+            method: "delete",
+            url: "/diseaseRight/toilet/delete",
+            headers: {
+              "Admin-Token": sessionStorage.getItem("token"),
+            },
+            data: [row.id],
+          });
+          // console.log(res);
+          if (res.data.success) {
+            this.$message.success("删除成功");
+            let totalPage = Math.ceil((this.totalCount - 1) / this.pageSize);
+            let currentPage =
+              this.curPage > totalPage ? totalPage : this.curPage;
+            this.curPage = currentPage < 1 ? 1 : currentPage;
+            this.getData(this.curPage);
+          } else {
+            this.$message.error("删除失败!");
+          }
+        })
+        .catch(() => {
+          this.$message.info("已取消");
+        });
+    },
+
+    //获取智慧停车列表数据
+    async getData2(val = 1) {
+      this.loading = true;
+      this.curPage2 = val;
+      let params = {
+        curPage: this.curPage2,
+        pageSize: this.pageSize2,
+        keyword: this.keyword2,
+      };
+      let res = await this.$axios({
+        url: "/diseaseRight/parking/page",
+        method: "get",
+        params,
+      });
+      //   console.log(res);
+      if (res.data.success) {
+        this.tableData2 = res.data.data.list;
+        this.totalCount2 = res.data.data.totalCount;
+      } else {
+        console.log("获取 智慧停车列表数据 失败");
+      }
+      this.loading = false;
+    },
+    // 添加停车场按钮回调
+    handleAdd2() {
+      this.dialogFormVisible2 = true;
+      this.title2 = "添加";
+      this.$nextTick(() => {
+        this.$refs.form2.resetFields();
+        this.form2 = {
+          name: "",
+          addrDesc: "",
+          openTime: "",
+          capacity: "",
+          longitudeAndLatitude: "",
+        };
+      });
+    },
+    // 编辑停车场按钮回调
+    editPark(row) {
+      this.dialogFormVisible2 = true;
+      this.title2 = "编辑";
+      this.$nextTick(() => {
+        this.$refs.form2.resetFields();
+        this.form2 = { ...row };
+      });
+    },
+    // 添加或编辑 停车场 请求
+    handleAddOrUpdata2(formName) {
+      this.$refs[formName].validate(async (valid) => {
+        if (valid) {
+          this.dialogFormVisible2 = false;
+          if (this.form2.id) {
+            // 编辑请求
+            let res = await this.$axios({
+              method: "put",
+              url: "/diseaseRight/parking/update",
+              headers: {
+                "Admin-Token": sessionStorage.getItem("token"),
+              },
+              data: this.form2,
+            });
+            // console.log(res);
+            if (res.data.success) {
+              this.getData2(this.curPage2);
+              this.$message.success("编辑成功!");
+            } else {
+              this.$message.error(res.data.message);
+            }
+          } else {
+            // 添加请求
+            let res = await this.$axios({
+              method: "post",
+              url: "/diseaseRight/parking/save",
+              headers: {
+                "Admin-Token": sessionStorage.getItem("token"),
+              },
+              data: this.form2,
+            });
+            // console.log(res);
+            if (res.data.success) {
+              this.getData2(1);
+              this.$message.success("添加成功!");
+            } else {
+              this.$message.error(res.data.message);
+            }
+          }
+        } else {
+          console.log("提交失败!!");
+          return false;
+        }
+      });
+    },
+    // 删除停车场按钮回调
+    deletePark(row) {
+      this.$confirm("确定删除吗?", "提示", {
+        cancelButtonText: "取消",
+        confirmButtonText: "确定",
+        type: "warning",
+      })
+        .then(async () => {
+          let res = await this.$axios({
+            method: "delete",
+            url: "/diseaseRight/parking/delete",
+            headers: {
+              "Admin-Token": sessionStorage.getItem("token"),
+            },
+            data: [row.id],
+          });
+          // console.log(res);
+          if (res.data.success) {
+            this.$message.success("删除成功");
+            let totalPage = Math.ceil((this.totalCount2 - 1) / this.pageSize2);
+            let currentPage =
+              this.curPage2 > totalPage ? totalPage : this.curPage2;
+            this.curPage2 = currentPage < 1 ? 1 : currentPage;
+            this.getData2(this.curPage2);
+          } else {
+            this.$message.error("删除失败!");
+          }
+        })
+        .catch(() => {
+          this.$message.info("已取消");
+        });
+    },
+  },
+};
+</script>
+
+<style scoped>
+.first-row {
+  display: flex;
+  align-items: center;
+  height: 50px;
+}
+.tag {
+  width: 108px;
+  height: 40px;
+  font-size: 24px;
+  font-family: Microsoft YaHei-3970(82674968);
+  font-weight: bold;
+  color: #000000;
+  line-height: 54px;
+}
+.pagination_smoke {
+  text-align: center;
+}
+</style>

+ 238 - 0
src/components/zhuanghaoguanli/zhuanghaoguanli.css

@@ -0,0 +1,238 @@
+/* dev-mgr */
+.first-row {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	height: 50px;
+}
+
+.second-row {
+	height: 80px;
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	padding-top: 40px;
+}
+
+.third-row {
+	margin-top: 10px;
+}
+
+.tag {
+	width: 108px;
+	height: 40px;
+	font-size: 24px;
+	font-family: Microsoft YaHei-3970(82674968);
+	font-weight: bold;
+	color: #000000;
+	line-height: 54px;
+}
+
+.demo-form-inline {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+}
+
+>>>.el-form-item__label {
+	height: 40px;
+	font-size: 22px;
+	font-family: Microsoft YaHei-3970(82674968);
+	font-weight: 400;
+	color: #333333;
+	line-height: 40px;
+}
+
+.shuibiaoId>>>.el-input__inner {
+	width: 240px;
+	height: 40px;
+	border: 1px solid #4D4D4D;
+	border-radius: 4px;
+	font-size: 20px;
+}
+
+.el-button {
+	margin: 0 60px 0 40px;
+	width: 100px;
+	height: 40px;
+	background: #298DEF;
+	border-radius: 4px;
+	font-size: 18px;
+}
+
+.btn-add {
+	margin-top: -30px;
+}
+
+.btn-add .el-button {
+	width: 100px;
+	height: 40px;
+	background: #298DEF;
+	border-radius: 4px;
+	display: flex;
+	align-items: center;
+}
+
+>>>.el-icon-add {
+	width: 22px;
+	height: 22px;
+	background: url(../../../static/images/add.png) center center no-repeat;
+	background-size: 18px 18px;
+}
+
+>>>.el-table__header {
+	font-size: 20px;
+	font-family: Microsoft YaHei-3970(82674968);
+	font-weight: 400;
+}
+
+>>>.el-table__header .cell {
+	color: #010101;
+}
+
+>>>.el-checkbox,
+>>>.el-checkbox__inner {
+	width: 24px;
+	height: 24px;
+}
+
+>>>.el-checkbox__inner::after {
+	margin: 3px 0 0 4px;
+	width: 4px;
+	height: 10px;
+}
+
+>>>.el-table__row .cell {
+	height: 35px;
+	line-height: 35px;
+	font-size: 18px;
+	color: #333333;
+}
+
+>>>.el-table__row .cell .el-button {
+	background: none;
+	margin: 0 20px 0 0;
+	width: 50px;
+	height: 35px;
+	font-size: 18px;
+}
+
+.del-btn {
+	color: #ff0000 !important;
+}
+
+.el-pagination>>>.el-icon {
+	width: 38px;
+	height: 38px;
+	line-height: 38px;
+	border: 1px solid #626262;
+	border-radius: 2px;
+	font-size: 18px;
+}
+
+.el-pagination>>>.number,
+.el-pagination>>>.more {
+	margin: 0 5px;
+	width: 40px;
+	height: 40px;
+	line-height: 40px;
+	border: 1px solid #626262;
+	border-radius: 2px;
+	font-size: 18px;
+}
+
+.table-footer {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+}
+
+.pages {
+	width: 100%;
+	display: flex;
+	justify-content: center;
+}
+
+>>>.el-pager li.active {
+	color: #FFF;
+	font-weight: bold;
+	background-color: #298DEF
+}
+
+.export-table {
+	width: 200px;
+	display: flex;
+	font-size: 20px;
+	font-family: Microsoft YaHei-3970(82674968);
+	font-weight: 400;
+	color: #FFFFFF;
+	line-height: 54px;
+}
+
+>>>.el-dialog__title {
+	font-size: 24px;
+}
+
+.el-dialog .el-form {
+	margin-top: 20px;
+}
+
+>>>.el-form-item__label {
+	font-size: 20px;
+}
+
+>>>.el-dialog__body .el-input__inner {
+	font-size: 18px;
+}
+
+.dialog-footer>>>.el-button--default {
+	border: 1px solid #298DEF;
+	border-radius: 4px;
+	font-size: 24px;
+	font-family: Microsoft YaHei-3970(82674968);
+	font-weight: 400;
+	color: #298DEF;
+	height: 46px;
+	background-color: #FFFFFF;
+}
+
+.dialog-footer>>>.el-button--primary {
+	background: #298DEF;
+	border-radius: 4px;
+	font-size: 24px;
+	font-family: Microsoft YaHei-3970(82674968);
+	font-weight: 400;
+	color: #FFFFFF;
+	height: 46px;
+}
+
+.my-dialog {
+	display: flex;
+	justify-content: center;
+	align-items: center;
+}
+
+.box-icon {
+	display: flex;
+	justify-content: center;
+	margin: 20px auto;
+	background: url(../../../static/images/info.png) no-repeat;
+	background-size: 107px 107px;
+	width: 107px;
+	height: 107px;
+}
+
+.del-msg {
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	font-size: 22px;
+	font-family: Microsoft YaHei-3970(82674968);
+	font-weight: 400;
+	color: #333333;
+	line-height: 54px;
+	text-align: center;
+}
+
+
+/* dev-mgr */

+ 653 - 0
src/components/zhuanghaoguanli/zhuanghaoguanli.vue

@@ -0,0 +1,653 @@
+<template>
+	<div>
+		<el-row>
+			<el-col :span="24" class="first-row">
+				<div class="tag">账号管理</div>
+			</el-col>
+		</el-row>
+		<el-row>
+			<el-col :span="24" class="second-row">
+				<!-- <el-form :inline="true" class="demo-form-inline">
+					<el-form-item label="账号:" class="shuibiaoId">
+						<el-input v-model="account" placeholder="请输入账号" clearable maxlength="16"></el-input>
+					</el-form-item>
+					<el-form-item>
+						<el-button type="primary" @click="onSearch">查找</el-button>
+					</el-form-item>
+				</el-form> -->
+				<div class="btn-add">
+					<el-button type="primary" icon="el-icon-add" @click="handleAdd">添加</el-button>
+				</div>
+			</el-col>
+		</el-row>
+		<hr style="background-color: #CCCCCC;height: 1px;border: 0;">
+		<el-row>
+			<el-col :span="24" class="third-row">
+				<el-table ref="multipleTable" :data="tableData" tooltip-effect="dark" style="width: 100%"
+					highlight-current-row>
+					<!-- <el-table-column label="昵称" align="center">
+						<template slot-scope="scope">{{ scope.row.name }}</template>
+					</el-table-column> -->
+					<el-table-column prop="userName" label="账号" align="center"></el-table-column>
+					<el-table-column prop="adminType" label="类别" align="center" :formatter="adminType">
+					</el-table-column>
+					<el-table-column prop="status" label="状态" show-overflow-tooltip :formatter="formatStatus">
+					</el-table-column>
+					<el-table-column label="操作" align="center" width="80">
+						<el-button type="text" class="del-btn" slot-scope="scope" v-if="myUserType === '0'"
+							@click="handleDelete(scope.$index, scope.row)">删除
+						</el-button>
+					</el-table-column>
+					<el-table-column width="130">
+						<el-button type="text" slot-scope="scope" v-if="myUserType === '0'"
+							@click="handleEdit(scope.$index, scope.row)">编辑
+						</el-button>
+					</el-table-column>
+				</el-table>
+				<div style="margin-top: 20px" class="table-footer">
+					<div class="pages">
+						<el-pagination layout="prev, pager, next" :total="total_rows" :current-page.sync="current_page"
+							:hide-on-single-page="true" :page-size="page_rows" @current-change="handleCurrentChange">
+						</el-pagination>
+					</div>
+				</div>
+			</el-col>
+		</el-row>
+		<el-row>
+			<el-col :span="24" class="forth-row">
+				<!-- 添加对话框 -->
+				<el-dialog title="添加账号" :visible.sync="adddialogFormVisible" width="500px" top="0vh" class="my-dialog"
+					:close-on-click-modal="false" :close-on-press-escape="false">
+					<hr
+						style="width: 100%; position: absolute; top: 60px; left: 0px;background-color: #CCCCCC;height: 1px;border: 0;">
+					<el-form :model="addform" :rules="addRules" ref="addform">
+						<el-form-item label="账号:" prop="userName" :label-width="formLabelWidth">
+							<el-input v-model="addform.userName" autocomplete="off" minlength="5" maxlength="16">
+							</el-input>
+						</el-form-item>
+						<el-form-item label="密码:" prop="password" :label-width="formLabelWidth">
+							<el-input v-model="addform.password" type="password" minlength="5" autocomplete="off"
+								maxlength="16">
+							</el-input>
+						</el-form-item>
+						<el-form-item label="确认密码:" prop="comfirmPass" :label-width="formLabelWidth">
+							<el-input v-model="addform.comfirmPass" type="password" minlength="5" autocomplete="off"
+								maxlength="16">
+							</el-input>
+						</el-form-item>
+						<el-form-item label="类别:" prop="adminType" :label-width="formLabelWidth">
+							<el-radio v-model="addform.adminType" label="1">管理员</el-radio>
+							<el-radio v-model="addform.adminType" label="0">超级管理员</el-radio>
+						</el-form-item>
+						<el-form-item label="状态:" prop="status" :label-width="formLabelWidth">
+							<el-radio v-model="addform.status" label="1">正常</el-radio>
+							<el-radio v-model="addform.status" label="0">冻结</el-radio>
+						</el-form-item>
+					</el-form>
+					<div slot="footer" class="dialog-footer">
+						<el-button @click="adddialogFormVisible = false">取 消</el-button>
+						<el-button type="primary" @click="handleAddRow('addform')">确 定</el-button>
+					</div>
+				</el-dialog>
+				<!-- 编辑对话框 -->
+				<el-dialog title="编辑" :visible.sync="editdialogFormVisible" width="500px" top="0vh" class="my-dialog"
+					:close-on-click-modal="false" :close-on-press-escape="false">
+					<hr
+						style="width: 100%; position: absolute; top: 60px; left: 0px;background-color: #CCCCCC;height: 1px;border: 0;">
+					<el-form :model="form" :rules="formRules" ref="form">
+						<el-form-item label="账号:" prop="userName" :label-width="formLabelWidth">
+							<el-input ref="zhanghao" v-model="form.userName" autocomplete="off" maxlength="16">
+							</el-input>
+						</el-form-item>
+						<!-- <el-form-item label="原密码:" prop="oldPassword" :label-width="formLabelWidth">
+							<el-input ref="yuanmima" v-model="form.oldPassword" type="password" autocomplete="off"
+								maxlength="16">
+							</el-input>
+						</el-form-item> -->
+						<el-form-item label="新密码:" prop="password" :label-width="formLabelWidth">
+							<el-input ref="xinmima" v-model="form.password" autocomplete="off" type="password"
+								maxlength="16">
+							</el-input>
+						</el-form-item>
+						<el-form-item label="确认新密码:" prop="comfirmPass" :label-width="formLabelWidth">
+							<el-input ref="querenmima" v-model="form.comfirmPass" autocomplete="off" type="password"
+								maxlength="16">
+							</el-input>
+						</el-form-item>
+						<el-form-item label="类别" prop="adminType" :label-width="formLabelWidth">
+							<el-radio v-model="form.adminType" label="1">管理员</el-radio>
+							<el-radio v-model="form.adminType" label="0">超级管理员</el-radio>
+						</el-form-item>
+						<el-form-item label="状态:" prop="status" :label-width="formLabelWidth">
+							<el-radio v-model="form.status" label="1">正常</el-radio>
+							<el-radio v-model="form.status" label="0">冻结</el-radio>
+						</el-form-item>
+					</el-form>
+					<div slot="footer" class="dialog-footer">
+						<el-button @click="editdialogFormVisible = false">取 消</el-button>
+						<el-button type="primary" @click="handleEditRow('form')">确 定</el-button>
+					</div>
+				</el-dialog>
+				<!-- 删除对话框 -->
+				<el-dialog :visible.sync="delDialogVisible" width="500px" center top="0vh" class="my-dialog"
+					:close-on-click-modal="false" :close-on-press-escape="false">
+					<div class="box-icon"></div>
+					<span class="del-msg">确定删除【{{del_account}}】账号吗?</span>
+					<span slot="footer" class="dialog-footer">
+						<el-button @click="delDialogVisible = false">取 消</el-button>
+						<el-button type="primary" @click="getDelPwd">确 定</el-button>
+						<!-- <el-button type="primary" @click="handleDelRow">确 定</el-button> -->
+					</span>
+				</el-dialog>
+				<!-- 删除账号密码验证对话框 -->
+				<!-- <el-dialog title="验证密码" :visible.sync="delDialogEnterPwdVisible" width="500px" top="0vh"
+					class="my-dialog" :close-on-click-modal="false" :close-on-press-escape="false">
+					<hr
+						style="width: 100%; position: absolute; top: 60px; left: 0px;background-color: #CCCCCC;height: 1px;border: 0;">
+					<el-form :model="delConfirmPwdform" :rules="delConfirmPwdRules" ref="delConfirmPwdform">
+						<el-form-item label="请输入密码:" prop="delPwd" :label-width="formLabelWidth">
+							<el-input ref="delPwd" v-model="delConfirmPwdform.delPwd" type="password" autocomplete="off"
+								maxlength="16">
+							</el-input>
+						</el-form-item>
+					</el-form>
+					<div slot="footer" class="dialog-footer">
+						<el-button @click="delDialogEnterPwdVisible = false">取 消</el-button>
+						<el-button type="primary" @click="getDelPwd('delConfirmPwdform')">确 定</el-button>
+					</div>
+				</el-dialog> -->
+			</el-col>
+		</el-row>
+	</div>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				myUserType: '',
+				addform: { // 添加框的数据绑定
+					userName: '',
+					password: '',
+					comfirmPass: '',
+					adminType: '1',
+					status: '1',
+				},
+				addRules: {
+					userName: [{
+							required: true,
+							message: '请输入账号',
+							trigger: 'blur'
+						},
+						{
+							min: 5,
+							max: 16,
+							message: '账号长度不小于5位',
+							trigger: 'blur'
+						}
+					],
+					password: [{
+							required: true,
+							message: '请输入密码',
+							trigger: 'blur'
+						},
+						{
+							min: 5,
+							max: 16,
+							message: '密码长度不小于5位',
+							trigger: 'blur'
+						}
+					],
+					comfirmPass: [{
+							required: true,
+							message: '请输入确认密码',
+							trigger: 'blur'
+						},
+						{
+							min: 5,
+							max: 16,
+							message: '确认密码长度不小于5位',
+							trigger: 'blur'
+						}
+					]
+				},
+				form: { // 编辑框的数据绑定
+					id: 0,
+					userName: '',
+					adminType: '1',
+					status: '1',
+					// oldPassword: '',
+					password: '',
+					comfirmPass: ''
+				},
+				formRules: {
+					name: [{
+							required: true,
+							message: '请输入昵称',
+							trigger: 'blur'
+						},
+						{
+							min: 5,
+							max: 16,
+							message: '昵称长度不小于5位',
+							trigger: 'blur'
+						}
+					],
+					number: [{
+							required: true,
+							message: '请输入账号',
+							trigger: 'blur'
+						},
+						{
+							min: 5,
+							max: 16,
+							message: '账号长度不小于5位',
+							trigger: 'blur'
+						}
+					],
+					// oldPassword: [{
+					// 		required: true,
+					// 		message: '请输入原密码',
+					// 		trigger: 'blur'
+					// 	},
+					// 	{
+					// 		min: 5,
+					// 		max: 16,
+					// 		message: '原密码长度不小于5位',
+					// 		trigger: 'blur'
+					// 	}
+					// ],
+					password: [{
+							required: true,
+							message: '请输入新密码',
+							trigger: 'blur'
+						},
+						{
+							min: 5,
+							max: 16,
+							message: '新密码长度不小于5位',
+							trigger: 'blur'
+						}
+					],
+					comfirmPass: [{
+							required: true,
+							message: '请输入确认新密码',
+							trigger: 'blur'
+						},
+						{
+							min: 5,
+							max: 16,
+							message: '确认新密码长度不小于5位',
+							trigger: 'blur'
+						}
+					]
+				},
+				delConfirmPwdform: {
+					delPwd: '' // 被删除的账号的密码
+				},
+				// delConfirmPwdRules: {
+				// 	delPwd: [{
+				// 			required: true,
+				// 			message: '请输入密码进行验证',
+				// 			trigger: 'blur'
+				// 		},
+				// 		{
+				// 			min: 5,
+				// 			max: 16,
+				// 			message: '密码长度不小于5位',
+				// 			trigger: 'blur'
+				// 		}
+				// 	]
+				// },
+				del_id: 0, // 被删除的id
+				del_account: '', // 被删除的账号
+				account: '', // 需要查找的账号
+				login_account: '', // 登陆的账号
+				adddialogFormVisible: false, // 控制添加对话框显示、隐藏
+				editdialogFormVisible: false, // 控制编辑对话框显示、隐藏
+				delDialogEnterPwdVisible: false, // 控制删除账号时输入密码对话框
+				delDialogVisible: false, // 控制删除对话框显示、隐藏
+				formLabelWidth: '146px', // label宽度
+				tableData: [], // 表格数据
+				current_page: 1, // 当前所在页码
+				page_rows: 8, // 每页显示的记录数
+				total_rows: 0, // 总记录数
+				token: ''
+			}
+		},
+		created() {
+			this.login_account = sessionStorage.getItem('uname')
+			this.token = sessionStorage.getItem('token')
+			this.myUserType = sessionStorage.getItem('userType')
+			// 获取账号列表
+			this.updateTable()
+		},
+		methods: {
+			adminType(e) {
+				if (e.adminType === '1') {
+					return '管理员'
+				} else if (e.adminType === '0') {
+					return '超级管理员'
+				}
+				return '普通用户'
+			},
+			formatStatus(e) {
+				if (e.status === '1') {
+					return '正常'
+				} else if (e.status === '0') {
+					return '冻结'
+				}
+				return '未知'
+			},
+			/**
+			 * 改变页码
+			 * @param {Object} val
+			 */
+			handleCurrentChange(val) {
+				this.current_page = val
+
+				// 查询账号相关信息
+				this.updateTable()
+			},
+			/**
+			 * 管理员列表,填充表格变量
+			 */
+			updateTable() {
+				var _this = this
+				_this.tableData = []
+				let params = {
+					curPage: this.current_page,
+					pageSize: this.page_rows,
+					orderField: this.login_account
+				}
+				// if (this.account) {
+				// 	params.userName = this.account
+				// }
+				// _this.rows_total = 0
+				this.$axios({
+						method: "get",
+						url: "/diseaseRight/adminInfo/list",
+						headers: {
+							'Content-type': 'application/x-www-form-urlencoded;charset=utf-8'
+						},
+						data: params
+					})
+					.then(res => {
+						console.log(res.data);
+						if (res.data.success) {
+							_this.tableData = res.data.data.list
+							_this.total_rows = res.data.data.totalCount
+							var i = 0
+							for (; i < _this.tableData.length; i++) {
+								if (_this.tableData[i].userName == _this.login_account) {
+									sessionStorage.setItem('unic', _this.tableData[i].userName)
+									break
+								}
+							}
+							// _this.$emit('sonFun', _this.tableData[i].userName)
+						} else {
+							_this.$message.success('【获取账号】暂无数据!');
+						}
+					})
+					.catch(err => {
+						// console.log(err);
+						_this.$message.error('【获取账号】请求异常: ' + err);
+					})
+			},
+			/**
+			 * 查找账号
+			 */
+			onSearch() {
+				// if (!this.account) {
+				// 	this.$message.error('请输入账号')
+				// 	return
+				// }
+
+				// 查询账号相关信息
+				this.updateTable()
+			},
+			/**
+			 * 添加账号
+			 */
+			handleAdd() {
+				this.adddialogFormVisible = true
+			},
+			/**
+			 * 添加一条账号
+			 */
+			handleAddRow(formName) {
+				this.$refs[formName].validate((valid) => {
+					if (valid) {
+						if (!String(this.addform.userName).trim()) {
+							this.$message.error('请输入账号')
+							return
+						}
+						if (!String(this.addform.password).trim()) {
+							this.$message.error('请输入密码')
+							return
+						}
+						if (!String(this.addform.comfirmPass).trim()) {
+							this.$message.error('请输入确认密码')
+							return
+						}
+						if (String(this.addform.password).trim() != String(this.addform.comfirmPass).trim()) {
+							this.$message.error('密码与确认密码不一致!')
+							return
+						}
+						var params = {
+							userName: String(this.addform.userName).trim(),
+							password: String(this.addform.password).trim(),
+							adminType: String(this.addform.adminType).trim(),
+							status: String(this.addform.status).trim()
+						}
+						var _this = this
+						this.$axios({
+								method: "post",
+								url: "/diseaseRight/adminInfo/save",
+								headers: {
+									'Admin-Token': this.token,
+									'Content-type': 'application/json; charset=utf-8'
+								},
+								data: params
+							})
+							.then(res => {
+								// console.log(res.data);
+								if (res.data.success) {
+									this.adddialogFormVisible = false
+									_this.$message.success('【账号添加】成功!');
+									_this.addform = {
+										userName: '',
+										password: '',
+										comfirmPass: '',
+										adminType: '1',
+										status: '1',
+									}
+									// 更新列表
+									this.updateTable()
+								} else if (res.data.message === "数据已存在") {
+									_this.$message.error('账号已存在');
+								} else {
+									_this.$message.error(res.data.message);
+								}
+							})
+							.catch(err => {
+								// console.log(err);
+								_this.$message.error('【账号】添加请求异常: ' + err);
+							})
+					} else {
+						// this.$message.error('表单验证失败!')
+						return false;
+					}
+				});
+			},
+			/**
+			 * 编辑对话框
+			 * @param {Object} index
+			 * @param {Object} row
+			 */
+			handleEdit(index, row) {
+				console.log(index, row);
+				this.editdialogFormVisible = true
+				this.form.id = row.id
+				this.form.userName = row.userName
+				this.form.adminType = row.adminType
+				this.form.status = row.status
+				// this.form.oldPassword = ''
+				this.form.password = ''
+				this.form.comfirmPass = ''
+			},
+			/**
+			 * 编辑更新指定的id所在的行
+			 */
+			handleEditRow(formName) {
+				var _this = this
+				_this.$refs[formName].validate((valid) => {
+					if (valid) {
+						if (!String(_this.form.userName).trim()) {
+							_this.$message.error('请输入账号')
+							_this.$refs['nicheng'].focus()
+							return
+						}
+						// if (!String(_this.form.oldPassword).trim()) {
+						// 	_this.$message.error('请输入原密码')
+						// 	_this.$refs['yuanmima'].focus()
+						// 	return
+						// }
+						if (!String(_this.form.password).trim()) {
+							_this.$message.error('请输入新密码')
+							_this.$refs['xinmima'].focus()
+							return
+						}
+						if (String(_this.form.password).trim() != String(_this.form.comfirmPass).trim()) {
+							_this.$message.error('新密码和确认新密码不一致!')
+							_this.$refs['querenmima'].focus()
+							return
+						}
+						if (!String(_this.form.adminType).trim()) {
+							_this.$message.error('请输入类别')
+							_this.$refs['zhanghao'].focus()
+							return
+						}
+						if (!String(_this.form.status).trim()) {
+							_this.$message.error('请输入状态')
+							_this.$refs['zhanghao'].focus()
+							return
+						}
+
+						let params = {
+							id: _this.form.id,
+							userName: String(_this.form.userName).trim(),
+							adminType: String(_this.form.adminType).trim(),
+							// oldpass: String(_this.form.oldPassword).trim(),
+							password: String(_this.form.password).trim(),
+							status: String(_this.form.status).trim()
+						}
+
+						_this.$axios({
+								method: "put",
+								url: "/diseaseRight/adminInfo/update",
+								headers: {
+									'Admin-Token': this.token,
+									'Content-type': 'application/json; charset=utf-8'
+								},
+								data: params
+							})
+							.then(res => {
+								console.log(res.data);
+								if (res.data.success) {
+									_this.editdialogFormVisible = false
+									_this.$message.success('【账号】修改成功!');
+
+									// 更新表格
+									_this.updateTable()
+
+									_this.form = {
+										id: 0,
+										userName: '',
+										adminType: '1',
+										status: '1',
+										// oldPassword: '',
+										password: '',
+										comfirmPass: ''
+									}
+								} else {
+									_this.$message.error('【账号】修改失败!' + res.data.msg);
+								}
+							})
+							.catch(err => {
+								// console.log(err);
+								_this.$message.error('【账号】修改请求异常: ' + err);
+							})
+					} else {
+						// _this.$message.error('表单验证失败!')
+						return false;
+					}
+				});
+			},
+			/**
+			 * 删除对话框
+			 * @param {Object} index
+			 * @param {Object} row
+			 */
+			handleDelete(index, row) {
+				this.delDialogVisible = true
+				this.del_account = row.userName
+				this.del_id = row.id
+			},
+			/**
+			 * 被删除账号的密码
+			 */
+			getDelPwd(formName) {
+				var _this = this
+				// var params = {
+				// 	id: _this.del_id
+				// }
+				_this.$axios({
+						method: "delete",
+						url: "/diseaseRight/adminInfo/delete/" + _this.del_id,
+						headers: {
+							'Admin-Token': this.token,
+							'Content-type': 'application/x-www-form-urlencoded;charset=utf-8'
+						},
+						// data: params
+					})
+					.then(res => {
+						// console.log(res.data);
+						if (res.data.success) {
+							_this.$message.success('账号【' + this.del_account + '】删除成功!');
+							_this.delDialogVisible = false
+							_this.updateTable()
+						} else {
+							_this.$message.error('账号【' + this.del_account + '】删除失败!');
+						}
+					})
+					.catch(err => {
+						// console.log(err);
+						_this.$message.error('账号【' + this.del_account + '】删除请求异常: ' + err);
+					})
+			},
+			/**
+			 * 删除指定的id所在的行
+			 */
+			// handleDelRow() {
+			// 	if (this.login_account == this.del_account) {
+			// 		this.delDialogVisible = false
+			// 		this.$message.error('不能删除当前登录账号!')
+			// 		return
+			// 	}
+
+			// 	this.delConfirmPwdform.delPwd = ''
+
+			// 	this.delDialogEnterPwdVisible = true
+
+			// 	setTimeout(() => {
+			// 		this.$refs['delPwd'].focus()
+			// 	}, 200)
+			// }
+		}
+	}
+</script>
+
+<style scoped>
+	@import url("zhuanghaoguanli.css");
+</style>

+ 54 - 0
src/main.js

@@ -0,0 +1,54 @@
+import Vue from 'vue'
+import App from './App'
+import router from './router'
+import Axios from "axios"
+
+// element - ui按需引入
+import {
+	Row, Col, Upload, Button, Select, Input, Menu, MenuItem, Form, FormItem, DatePicker, Table, TableColumn, Pagination, Dialog, Option, Message, MessageBox, Tabs, TabPane, Loading
+} from 'element-ui';
+
+// 注册使用element - ui组件
+Vue.use(Row)
+Vue.use(Col)
+Vue.use(Upload)
+Vue.use(Button)
+Vue.use(Select)
+Vue.use(Input)
+Vue.use(Menu)
+Vue.use(MenuItem)
+Vue.use(Form)
+Vue.use(FormItem)
+Vue.use(DatePicker)
+Vue.use(Table)
+Vue.use(TableColumn)
+Vue.use(Pagination)
+Vue.use(Dialog)
+Vue.use(Option)
+Vue.use(Tabs)
+Vue.use(TabPane)
+Vue.use(Loading.directive);
+Vue.prototype.$loading = Loading.service;
+
+Vue.prototype.$confirm = MessageBox.confirm;
+Vue.prototype.$message = Message;
+
+Vue.prototype.$axios = Axios;
+
+Vue.config.productionTip = false
+
+Vue.directive('fo', {
+	inserted(el, binding, vnode) {
+		// 聚焦元素
+		el.querySelector('input').focus()
+	}
+})
+
+new Vue({
+	el: '#app',
+	router,
+	components: {
+		App
+	},
+	template: '<App/>'
+})

+ 71 - 0
src/router/index.js

@@ -0,0 +1,71 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+import Login from '@/components/login/login' // 登陆
+import Index from '@/components/index/index' // 首页
+import ZHGL from '@/components/zhuanghaoguanli/zhuanghaoguanli' // 账户管理
+
+import NewsFocus from '@/components/newsFocus' // 新闻聚焦
+import EarlyWarning from '@/components/earlyWarning' // 旅游人数预警
+import Consumption from '@/components/consumption' // 消费占比
+import EventPlanning from '@/components/eventPlanning' // 活动策划
+import PeopleCoefficient from '@/components/peopleCoefficient' // 人次系数
+import Serve from '@/components/serve' // 智慧服务
+import Form from '@/components/form' // 报表
+
+Vue.use(Router)
+
+export default new Router({
+	// mode: 'history',
+	// base: '/travel/',
+	routes: [
+		{
+			path: '/',
+			name: 'Login',
+			component: Login
+		}, {
+			path: '/travel/index',
+			name: 'index',
+			redirect: '/travel/index/consumption', // 设置默认打开的页面
+			component: Index,
+			children: [{
+				path: 'zhgl',
+				name: 'ZHGL',
+				component: ZHGL // 账户管理
+			},
+			{
+				path: 'consumption',
+				name: 'consumption',
+				component: Consumption // 消费占比
+			},
+			{
+				path: 'newsFocus',
+				name: 'newsFocus',
+				component: NewsFocus // 新闻聚焦
+			},
+			{
+				path: 'earlyWarning',
+				name: 'earlyWarning',
+				component: EarlyWarning // 旅游人数预警
+			}, {
+				path: 'eventPlanning',
+				name: 'eventPlanning',
+				component: EventPlanning // 活动策划
+			},
+			{
+				path: 'peopleCoefficient',
+				name: 'peopleCoefficient',
+				component: PeopleCoefficient // 人次系数
+			},
+			{
+				path: 'serve',
+				name: 'serve',
+				component: Serve // 智慧服务
+			},
+			{
+				path: 'form',
+				name: 'form',
+				component: Form // 报表
+			},
+			]
+		}]
+})

+ 59 - 0
src/store/index.js

@@ -0,0 +1,59 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+Vue.use(Vuex);
+let store = new Vuex.Store({
+	state: {
+		loginStatus: 0,
+		token: '',
+		userName: ''
+	},
+	mutations: {
+		loginSuccess(state) {
+			state.userName = db.get('userName');
+			state.loginStatus = 1
+		},
+		loginFail(state) {
+			state.loginStatus = 0
+		},
+		updateToken(state, token) {
+
+			state.token = token;
+			db.set('token', token);
+
+		},
+		loginOut(state) {
+			db.remove('token');
+			state.loginStatus = 0;
+			state.token = "";
+		}
+	},
+	actions: {
+		loginAction({
+			commit
+		}, token) {
+
+			commit('loginSuccess');
+			commit('updateToken', token)
+		},
+		tokenAction({
+			commit
+		}, token) {
+			commit('updateToken', token)
+		},
+		loginOutAction({
+			commit
+		}) {
+			commit('loginOut')
+		}
+
+	}
+})
+// 页面刷新时,重新赋值token
+let token = db.get('token');
+if (token) {
+	store.commit('updateToken', token);
+	store.commit('loginSuccess')
+}
+
+export default store

+ 179 - 0
src/vendor/Blob.js

@@ -0,0 +1,179 @@
+/* eslint-disable */
+/* Blob.js
+ * A Blob implementation.
+ * 2014-05-27
+ *
+ * By Eli Grey, http://eligrey.com
+ * By Devin Samarin, https://github.com/eboyjr
+ * License: X11/MIT
+ *   See LICENSE.md
+ */
+
+/*global self, unescape */
+/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
+ plusplus: true */
+
+/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
+
+(function (view) {
+    "use strict";
+
+    view.URL = view.URL || view.webkitURL;
+
+    if (view.Blob && view.URL) {
+        try {
+            new Blob;
+            return;
+        } catch (e) {}
+    }
+
+    // Internally we use a BlobBuilder implementation to base Blob off of
+    // in order to support older browsers that only have BlobBuilder
+    var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) {
+            var
+                get_class = function(object) {
+                    return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
+                }
+                , FakeBlobBuilder = function BlobBuilder() {
+                    this.data = [];
+                }
+                , FakeBlob = function Blob(data, type, encoding) {
+                    this.data = data;
+                    this.size = data.length;
+                    this.type = type;
+                    this.encoding = encoding;
+                }
+                , FBB_proto = FakeBlobBuilder.prototype
+                , FB_proto = FakeBlob.prototype
+                , FileReaderSync = view.FileReaderSync
+                , FileException = function(type) {
+                    this.code = this[this.name = type];
+                }
+                , file_ex_codes = (
+                    "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
+                    + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
+                ).split(" ")
+                , file_ex_code = file_ex_codes.length
+                , real_URL = view.URL || view.webkitURL || view
+                , real_create_object_URL = real_URL.createObjectURL
+                , real_revoke_object_URL = real_URL.revokeObjectURL
+                , URL = real_URL
+                , btoa = view.btoa
+                , atob = view.atob
+
+                , ArrayBuffer = view.ArrayBuffer
+                , Uint8Array = view.Uint8Array
+                ;
+            FakeBlob.fake = FB_proto.fake = true;
+            while (file_ex_code--) {
+                FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
+            }
+            if (!real_URL.createObjectURL) {
+                URL = view.URL = {};
+            }
+            URL.createObjectURL = function(blob) {
+                var
+                    type = blob.type
+                    , data_URI_header
+                    ;
+                if (type === null) {
+                    type = "application/octet-stream";
+                }
+                if (blob instanceof FakeBlob) {
+                    data_URI_header = "data:" + type;
+                    if (blob.encoding === "base64") {
+                        return data_URI_header + ";base64," + blob.data;
+                    } else if (blob.encoding === "URI") {
+                        return data_URI_header + "," + decodeURIComponent(blob.data);
+                    } if (btoa) {
+                        return data_URI_header + ";base64," + btoa(blob.data);
+                    } else {
+                        return data_URI_header + "," + encodeURIComponent(blob.data);
+                    }
+                } else if (real_create_object_URL) {
+                    return real_create_object_URL.call(real_URL, blob);
+                }
+            };
+            URL.revokeObjectURL = function(object_URL) {
+                if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
+                    real_revoke_object_URL.call(real_URL, object_URL);
+                }
+            };
+            FBB_proto.append = function(data/*, endings*/) {
+                var bb = this.data;
+                // decode data to a binary string
+                if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
+                    var
+                        str = ""
+                        , buf = new Uint8Array(data)
+                        , i = 0
+                        , buf_len = buf.length
+                        ;
+                    for (; i < buf_len; i++) {
+                        str += String.fromCharCode(buf[i]);
+                    }
+                    bb.push(str);
+                } else if (get_class(data) === "Blob" || get_class(data) === "File") {
+                    if (FileReaderSync) {
+                        var fr = new FileReaderSync;
+                        bb.push(fr.readAsBinaryString(data));
+                    } else {
+                        // async FileReader won't work as BlobBuilder is sync
+                        throw new FileException("NOT_READABLE_ERR");
+                    }
+                } else if (data instanceof FakeBlob) {
+                    if (data.encoding === "base64" && atob) {
+                        bb.push(atob(data.data));
+                    } else if (data.encoding === "URI") {
+                        bb.push(decodeURIComponent(data.data));
+                    } else if (data.encoding === "raw") {
+                        bb.push(data.data);
+                    }
+                } else {
+                    if (typeof data !== "string") {
+                        data += ""; // convert unsupported types to strings
+                    }
+                    // decode UTF-16 to binary string
+                    bb.push(unescape(encodeURIComponent(data)));
+                }
+            };
+            FBB_proto.getBlob = function(type) {
+                if (!arguments.length) {
+                    type = null;
+                }
+                return new FakeBlob(this.data.join(""), type, "raw");
+            };
+            FBB_proto.toString = function() {
+                return "[object BlobBuilder]";
+            };
+            FB_proto.slice = function(start, end, type) {
+                var args = arguments.length;
+                if (args < 3) {
+                    type = null;
+                }
+                return new FakeBlob(
+                    this.data.slice(start, args > 1 ? end : this.data.length)
+                    , type
+                    , this.encoding
+                );
+            };
+            FB_proto.toString = function() {
+                return "[object Blob]";
+            };
+            FB_proto.close = function() {
+                this.size = this.data.length = 0;
+            };
+            return FakeBlobBuilder;
+        }(view));
+
+    view.Blob = function Blob(blobParts, options) {
+        var type = options ? (options.type || "") : "";
+        var builder = new BlobBuilder();
+        if (blobParts) {
+            for (var i = 0, len = blobParts.length; i < len; i++) {
+                builder.append(blobParts[i]);
+            }
+        }
+        return builder.getBlob(type);
+    };
+}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));

+ 141 - 0
src/vendor/Export2Excel.js

@@ -0,0 +1,141 @@
+/* eslint-disable */
+require('script-loader!file-saver');
+require('./Blob.js');
+require('script-loader!xlsx/dist/xlsx.core.min');
+function generateArray(table) {
+    var out = [];
+    var rows = table.querySelectorAll('tr');
+    var ranges = [];
+    for (var R = 0; R < rows.length; ++R) {
+        var outRow = [];
+        var row = rows[R];
+        var columns = row.querySelectorAll('td');
+        for (var C = 0; C < columns.length; ++C) {
+            var cell = columns[C];
+            var colspan = cell.getAttribute('colspan');
+            var rowspan = cell.getAttribute('rowspan');
+            var cellValue = cell.innerText;
+            if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;
+
+            //Skip ranges
+            ranges.forEach(function (range) {
+                if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
+                    for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
+                }
+            });
+
+            //Handle Row Span
+            if (rowspan || colspan) {
+                rowspan = rowspan || 1;
+                colspan = colspan || 1;
+                ranges.push({ s: { r: R, c: outRow.length }, e: { r: R + rowspan - 1, c: outRow.length + colspan - 1 } });
+            }
+            ;
+
+            //Handle Value
+            outRow.push(cellValue !== "" ? cellValue : null);
+
+            //Handle Colspan
+            if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
+        }
+        out.push(outRow);
+    }
+    return [out, ranges];
+};
+
+function datenum(v, date1904) {
+    if (date1904) v += 1462;
+    var epoch = Date.parse(v);
+    return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
+}
+
+function sheet_from_array_of_arrays(data, opts) {
+    var ws = {};
+    var range = { s: { c: 10000000, r: 10000000 }, e: { c: 0, r: 0 } };
+    for (var R = 0; R != data.length; ++R) {
+        for (var C = 0; C != data[R].length; ++C) {
+            if (range.s.r > R) range.s.r = R;
+            if (range.s.c > C) range.s.c = C;
+            if (range.e.r < R) range.e.r = R;
+            if (range.e.c < C) range.e.c = C;
+            var cell = { v: data[R][C] };
+            if (cell.v == null) continue;
+            var cell_ref = XLSX.utils.encode_cell({ c: C, r: R });
+
+            if (typeof cell.v === 'number') cell.t = 'n';
+            else if (typeof cell.v === 'boolean') cell.t = 'b';
+            else if (cell.v instanceof Date) {
+                cell.t = 'n';
+                cell.z = XLSX.SSF._table[14];
+                cell.v = datenum(cell.v);
+            }
+            else cell.t = 's';
+
+            ws[cell_ref] = cell;
+        }
+    }
+    if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
+    return ws;
+}
+
+function Workbook() {
+    if (!(this instanceof Workbook)) return new Workbook();
+    this.SheetNames = [];
+    this.Sheets = {};
+}
+
+function s2ab(s) {
+    var buf = new ArrayBuffer(s.length);
+    var view = new Uint8Array(buf);
+    for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
+    return buf;
+}
+
+export function export_table_to_excel(id) {
+    var theTable = document.getElementById(id);
+    console.log('a')
+    var oo = generateArray(theTable);
+    var ranges = oo[1];
+
+    /* original data */
+    var data = oo[0];
+    var ws_name = "SheetJS";
+    console.log(data);
+
+    var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
+
+    /* add ranges to worksheet */
+    // ws['!cols'] = ['apple', 'banan'];
+    ws['!merges'] = ranges;
+
+    /* add worksheet to workbook */
+    wb.SheetNames.push(ws_name);
+    wb.Sheets[ws_name] = ws;
+
+    var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' });
+
+    saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), "test.xlsx")
+}
+
+function formatJson(jsonData) {
+    console.log(jsonData)
+}
+export function export_json_to_excel(th, jsonData, defaultTitle) {
+
+    /* original data */
+
+    var data = jsonData;
+    data.unshift(th);
+    var ws_name = "SheetJS";
+
+    var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
+
+
+    /* add worksheet to workbook */
+    wb.SheetNames.push(ws_name);
+    wb.Sheets[ws_name] = ws;
+
+    var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' });
+    var title = defaultTitle || '列表'
+    saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), title + ".xlsx")
+}

+ 0 - 0
static/.gitkeep


二進制
static/images/add.png


二進制
static/images/bb.png


二進制
static/images/bg.png


二進制
static/images/diwen.png


二進制
static/images/exit.png


二進制
static/images/huodongcehua.png


二進制
static/images/info.png


二進制
static/images/logo.png


二進制
static/images/mima.png


二進制
static/images/renshuyujing.png


二進制
static/images/touxiang.jpg


二進制
static/images/xiaofeizhanbi.png


二進制
static/images/xinwenjujiao.png


二進制
static/images/yonghuguanli.png


二進制
static/images/yonghuming.png


二進制
static/images/zhengfangti.png


+ 13 - 0
static/interface/index.js

@@ -0,0 +1,13 @@
+// 配置主机地址和端口号(可以有多个,需要测试那个环境字节打开那个base即可)
+let base = "https://jtishfw.ncjti.edu.cn/jxch-smartmp"
+
+// 在线api接口路径,需要和项目后台确认
+let online_url = {
+
+	//管理员登录
+	login: base + "/jxch-smartmp-api/HotWaters/waterqueryAdmin.action",
+
+}
+
+//导出online_url对象
+export default online_url

+ 27 - 0
test/e2e/custom-assertions/elementCount.js

@@ -0,0 +1,27 @@
+// A custom Nightwatch assertion.
+// The assertion name is the filename.
+// Example usage:
+//
+//   browser.assert.elementCount(selector, count)
+//
+// For more information on custom assertions see:
+// http://nightwatchjs.org/guide#writing-custom-assertions
+
+exports.assertion = function (selector, count) {
+  this.message = 'Testing if element <' + selector + '> has count: ' + count
+  this.expected = count
+  this.pass = function (val) {
+    return val === this.expected
+  }
+  this.value = function (res) {
+    return res.value
+  }
+  this.command = function (cb) {
+    var self = this
+    return this.api.execute(function (selector) {
+      return document.querySelectorAll(selector).length
+    }, [selector], function (res) {
+      cb.call(self, res)
+    })
+  }
+}

+ 46 - 0
test/e2e/nightwatch.conf.js

@@ -0,0 +1,46 @@
+require('babel-register')
+var config = require('../../config')
+
+// http://nightwatchjs.org/gettingstarted#settings-file
+module.exports = {
+  src_folders: ['test/e2e/specs'],
+  output_folder: 'test/e2e/reports',
+  custom_assertions_path: ['test/e2e/custom-assertions'],
+
+  selenium: {
+    start_process: true,
+    server_path: require('selenium-server').path,
+    host: '127.0.0.1',
+    port: 4444,
+    cli_args: {
+      'webdriver.chrome.driver': require('chromedriver').path
+    }
+  },
+
+  test_settings: {
+    default: {
+      selenium_port: 4444,
+      selenium_host: 'localhost',
+      silent: true,
+      globals: {
+        devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port)
+      }
+    },
+
+    chrome: {
+      desiredCapabilities: {
+        browserName: 'chrome',
+        javascriptEnabled: true,
+        acceptSslCerts: true
+      }
+    },
+
+    firefox: {
+      desiredCapabilities: {
+        browserName: 'firefox',
+        javascriptEnabled: true,
+        acceptSslCerts: true
+      }
+    }
+  }
+}

+ 48 - 0
test/e2e/runner.js

@@ -0,0 +1,48 @@
+// 1. start the dev server using production config
+process.env.NODE_ENV = 'testing'
+
+const webpack = require('webpack')
+const DevServer = require('webpack-dev-server')
+
+const webpackConfig = require('../../build/webpack.prod.conf')
+const devConfigPromise = require('../../build/webpack.dev.conf')
+
+let server
+
+devConfigPromise.then(devConfig => {
+  const devServerOptions = devConfig.devServer
+  const compiler = webpack(webpackConfig)
+  server = new DevServer(compiler, devServerOptions)
+  const port = devServerOptions.port
+  const host = devServerOptions.host
+  return server.listen(port, host)
+})
+.then(() => {
+  // 2. run the nightwatch test suite against it
+  // to run in additional browsers:
+  //    1. add an entry in test/e2e/nightwatch.conf.js under "test_settings"
+  //    2. add it to the --env flag below
+  // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox`
+  // For more information on Nightwatch's config file, see
+  // http://nightwatchjs.org/guide#settings-file
+  let opts = process.argv.slice(2)
+  if (opts.indexOf('--config') === -1) {
+    opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js'])
+  }
+  if (opts.indexOf('--env') === -1) {
+    opts = opts.concat(['--env', 'chrome'])
+  }
+
+  const spawn = require('cross-spawn')
+  const runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' })
+
+  runner.on('exit', function (code) {
+    server.close()
+    process.exit(code)
+  })
+
+  runner.on('error', function (err) {
+    server.close()
+    throw err
+  })
+})

+ 19 - 0
test/e2e/specs/test.js

@@ -0,0 +1,19 @@
+// For authoring Nightwatch tests, see
+// http://nightwatchjs.org/guide#usage
+
+module.exports = {
+  'default e2e tests': function (browser) {
+    // automatically uses dev Server port from /config.index.js
+    // default: http://localhost:8080
+    // see nightwatch.conf.js
+    const devServer = browser.globals.devServerURL
+
+    browser
+      .url(devServer)
+      .waitForElementVisible('#app', 5000)
+      .assert.elementPresent('.hello')
+      .assert.containsText('h1', 'Welcome to Your Vue.js App')
+      .assert.elementCount('img', 1)
+      .end()
+  }
+}

+ 7 - 0
test/unit/.eslintrc

@@ -0,0 +1,7 @@
+{
+  "env": { 
+    "jest": true
+  },
+  "globals": { 
+  }
+}

+ 30 - 0
test/unit/jest.conf.js

@@ -0,0 +1,30 @@
+const path = require('path')
+
+module.exports = {
+  rootDir: path.resolve(__dirname, '../../'),
+  moduleFileExtensions: [
+    'js',
+    'json',
+    'vue'
+  ],
+  moduleNameMapper: {
+    '^@/(.*)$': '<rootDir>/src/$1'
+  },
+  transform: {
+    '^.+\\.js$': '<rootDir>/node_modules/babel-jest',
+    '.*\\.(vue)$': '<rootDir>/node_modules/vue-jest'
+  },
+  testPathIgnorePatterns: [
+    '<rootDir>/test/e2e'
+  ],
+  snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
+  setupFiles: ['<rootDir>/test/unit/setup'],
+  mapCoverage: true,
+  coverageDirectory: '<rootDir>/test/unit/coverage',
+  collectCoverageFrom: [
+    'src/**/*.{js,vue}',
+    '!src/main.js',
+    '!src/router/index.js',
+    '!**/node_modules/**'
+  ]
+}

+ 3 - 0
test/unit/setup.js

@@ -0,0 +1,3 @@
+import Vue from 'vue'
+
+Vue.config.productionTip = false

+ 11 - 0
test/unit/specs/HelloWorld.spec.js

@@ -0,0 +1,11 @@
+import Vue from 'vue'
+import HelloWorld from '@/components/HelloWorld'
+
+describe('HelloWorld.vue', () => {
+  it('should render correct contents', () => {
+    const Constructor = Vue.extend(HelloWorld)
+    const vm = new Constructor().$mount()
+    expect(vm.$el.querySelector('.hello h1').textContent)
+      .toEqual('Welcome to Your Vue.js App')
+  })
+})