James 4 سال پیش
کامیت
c0ed4c7a05
100فایلهای تغییر یافته به همراه17884 افزوده شده و 0 حذف شده
  1. 17 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. 27 0
      README.md
  8. 41 0
      build/build.js
  9. 54 0
      build/check-versions.js
  10. BIN
      build/logo.png
  11. 102 0
      build/utils.js
  12. 22 0
      build/vue-loader.conf.js
  13. 92 0
      build/webpack.base.conf.js
  14. 95 0
      build/webpack.dev.conf.js
  15. 149 0
      build/webpack.prod.conf.js
  16. 7 0
      config/dev.env.js
  17. 77 0
      config/index.js
  18. 4 0
      config/prod.env.js
  19. 7 0
      config/test.env.js
  20. 12 0
      index.html
  21. 13048 0
      package-lock.json
  22. 81 0
      package.json
  23. 22 0
      src/App.vue
  24. BIN
      src/assets/images/activity-title.png
  25. BIN
      src/assets/images/activity-type-top-bg.png
  26. BIN
      src/assets/images/arrow.png
  27. BIN
      src/assets/images/back.png
  28. BIN
      src/assets/images/close.png
  29. BIN
      src/assets/images/collection-title.png
  30. BIN
      src/assets/images/collection-type-top-bg.png
  31. BIN
      src/assets/images/exhibition-hot-hover.jpg
  32. BIN
      src/assets/images/exhibition-hot.jpg
  33. BIN
      src/assets/images/exhibition-preview-hover.jpg
  34. BIN
      src/assets/images/exhibition-preview.jpg
  35. BIN
      src/assets/images/exhibition-review-hover.jpg
  36. BIN
      src/assets/images/exhibition-review.jpg
  37. BIN
      src/assets/images/exhibition-right-arrow.png
  38. BIN
      src/assets/images/exhibition-title.png
  39. BIN
      src/assets/images/exhibition-type-top-bg.png
  40. BIN
      src/assets/images/header-bg.png
  41. BIN
      src/assets/images/home-slice-1.jpg
  42. BIN
      src/assets/images/information-activity-hover.jpg
  43. BIN
      src/assets/images/information-activity.jpg
  44. BIN
      src/assets/images/information-book-hover.jpg
  45. BIN
      src/assets/images/information-book.jpg
  46. BIN
      src/assets/images/information-infor-hover.jpg
  47. BIN
      src/assets/images/information-infor.jpg
  48. BIN
      src/assets/images/information-recentNews-hover.jpg
  49. BIN
      src/assets/images/information-recentNews.jpg
  50. BIN
      src/assets/images/information-title.png
  51. BIN
      src/assets/images/information-type-top-bg.png
  52. BIN
      src/assets/images/logo.png
  53. BIN
      src/assets/images/message-icon.png
  54. BIN
      src/assets/images/nav-logo.png
  55. BIN
      src/assets/images/paging-next.png
  56. BIN
      src/assets/images/paging-prev.png
  57. BIN
      src/assets/images/question-error.png
  58. BIN
      src/assets/images/question-tip-bg.png
  59. BIN
      src/assets/images/service-title.png
  60. BIN
      src/assets/images/service-type-top-bg.png
  61. BIN
      src/assets/images/survey-bg.png
  62. BIN
      src/assets/images/survey-con-li-bg.png
  63. BIN
      src/assets/images/survey-con-li-hover-bg.png
  64. BIN
      src/assets/images/survey-history-hover.jpg
  65. BIN
      src/assets/images/survey-history.jpg
  66. BIN
      src/assets/images/survey-introduce.png
  67. BIN
      src/assets/images/survey-introduction-hover.jpg
  68. BIN
      src/assets/images/survey-introduction.jpg
  69. BIN
      src/assets/images/survey-mechanism-hover.jpg
  70. BIN
      src/assets/images/survey-mechanism.jpg
  71. BIN
      src/assets/images/survey-mechanism.png
  72. BIN
      src/assets/images/survey-title.png
  73. BIN
      src/assets/images/survey-type-bottom-bg.png
  74. BIN
      src/assets/images/survey-type-con-bg.png
  75. BIN
      src/assets/images/survey-type-nav-bg.png
  76. BIN
      src/assets/images/survey-type-top-bg.png
  77. BIN
      src/assets/images/test-book.png
  78. BIN
      src/assets/images/test-exhibition.png
  79. BIN
      src/assets/images/test-survey-intr-pic.png
  80. BIN
      src/assets/logo.png
  81. 9 0
      src/assets/style/public.less
  82. 40 0
      src/assets/style/reset.less
  83. 6 0
      src/common/common.js
  84. 0 0
      src/common/data.js
  85. 73 0
      src/common/http.js
  86. 27 0
      src/components/HelloWorld.vue
  87. 186 0
      src/components/pagination/index.vue
  88. 49 0
      src/main.js
  89. 331 0
      src/pages/activity/activity-detail.vue
  90. 883 0
      src/pages/activity/activity-type.vue
  91. 145 0
      src/pages/activity/activity.vue
  92. 269 0
      src/pages/collection/collection-detail.vue
  93. 478 0
      src/pages/collection/collection-type.vue
  94. 157 0
      src/pages/collection/collection.vue
  95. 289 0
      src/pages/exhibition/exhibition-detail.vue
  96. 406 0
      src/pages/exhibition/exhibition-type.vue
  97. 184 0
      src/pages/exhibition/exhibition.vue
  98. 86 0
      src/pages/home/home.vue
  99. 339 0
      src/pages/information/information-detail.vue
  100. 0 0
      src/pages/information/information-type.vue

+ 17 - 0
.babelrc

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

+ 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/
+/dali-website/
+/website/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+/test/unit/coverage/
+
+# 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": {}
+  }
+}

+ 27 - 0
README.md

@@ -0,0 +1,27 @@
+# dali-website
+
+> 大理博物馆门户网站
+
+## Build Setup
+
+``` bash
+# install dependencies
+npm install
+
+# serve with hot reload at localhost:8080
+npm run dev
+
+# build for production with minification
+npm run build
+
+# build for production and view the bundle analyzer report
+npm run build --report
+
+# run unit tests
+npm run unit
+
+# run all tests
+npm test
+```
+
+For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).

+ 41 - 0
build/build.js

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

+ 54 - 0
build/check-versions.js

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

BIN
build/logo.png


+ 102 - 0
build/utils.js

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

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

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

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

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

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

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

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

+ 77 - 0
config/index.js

@@ -0,0 +1,77 @@
+'use strict'
+// Template version: 1.3.1
+// see http://vuejs-templates.github.io/webpack for documentation.
+
+const path = require('path')
+
+module.exports = {
+  dev: {
+
+    // Paths
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/',
+    proxyTable: {},
+
+    // Various Dev Server settings
+    host: 'localhost', // can be overwritten by process.env.HOST
+    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
+    autoOpenBrowser: false,
+    errorOverlay: true,
+    notifyOnErrors: true,
+    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
+
+    // Use Eslint Loader?
+    // If true, your code will be linted during bundling and
+    // linting errors and warnings will be shown in the console.
+    useEslint: true,
+    // If true, eslint errors and warnings will also be shown in the error overlay
+    // in the browser.
+    showEslintErrorsInOverlay: false,
+
+    /**
+     * Source Maps
+     */
+
+    // https://webpack.js.org/configuration/devtool/#development
+    devtool: 'cheap-module-eval-source-map',
+
+    // If you have problems debugging vue-files in devtools,
+    // set this to false - it *may* help
+    // https://vue-loader.vuejs.org/en/options.html#cachebusting
+    cacheBusting: true,
+
+    cssSourceMap: true
+  },
+
+  build: {
+    // Template for index.html
+    index: path.resolve(__dirname, '../dist/index.html'),
+
+    // Paths
+    assetsRoot: path.resolve(__dirname, '../dist'),
+    assetsSubDirectory: 'static',
+    assetsPublicPath: './',
+
+    // daliMuseum/website/
+    /**
+     * Source Maps
+     */
+
+    productionSourceMap: true,
+    // https://webpack.js.org/configuration/devtool/#production
+    devtool: '#source-map',
+
+    // Gzip off by default as many popular static hosts such as
+    // Surge or Netlify already gzip all static assets for you.
+    // Before setting to `true`, make sure to:
+    // npm install --save-dev compression-webpack-plugin
+    productionGzip: false,
+    productionGzipExtensions: ['js', 'css'],
+
+    // Run the build command with an extra argument to
+    // View the bundle analyzer report after build finishes:
+    // `npm run build --report`
+    // Set to `true` or `false` to always turn it on or off
+    bundleAnalyzerReport: process.env.npm_config_report
+  }
+}

+ 4 - 0
config/prod.env.js

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

+ 7 - 0
config/test.env.js

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

+ 12 - 0
index.html

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

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 13048 - 0
package-lock.json


+ 81 - 0
package.json

@@ -0,0 +1,81 @@
+{
+  "name": "dali-website",
+  "version": "1.0.0",
+  "description": "大理博物馆门户网站",
+  "author": "James <596992757@qq.com>",
+  "private": true,
+  "scripts": {
+    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
+    "start": "npm run dev",
+    "test": "npm run unit",
+    "lint": "eslint --ext .js,.vue src test/unit",
+    "build": "node build/build.js"
+  },
+  "dependencies": {
+    "axios": "^0.21.1",
+    "date-fns": "^2.23.0",
+    "element-ui": "^2.15.3",
+    "swiper": "^5.4.5",
+    "vue": "^2.5.2",
+    "vue-awesome-swiper": "^4.1.1",
+    "vue-router": "^3.0.1"
+  },
+  "devDependencies": {
+    "autoprefixer": "^7.1.2",
+    "babel-core": "^6.22.1",
+    "babel-eslint": "^8.2.1",
+    "babel-helper-vue-jsx-merge-props": "^2.0.3",
+    "babel-loader": "^7.1.1",
+    "babel-plugin-syntax-jsx": "^6.18.0",
+    "babel-plugin-transform-runtime": "^6.22.0",
+    "babel-plugin-transform-vue-jsx": "^3.5.0",
+    "babel-preset-env": "^1.3.2",
+    "babel-preset-stage-2": "^6.22.0",
+    "chalk": "^2.0.1",
+    "copy-webpack-plugin": "^4.0.1",
+    "css-loader": "^0.28.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",
+    "less": "^4.1.1",
+    "less-loader": "^5.0.0",
+    "node-notifier": "^5.1.2",
+    "optimize-css-assets-webpack-plugin": "^3.2.0",
+    "ora": "^1.2.0",
+    "portfinder": "^1.0.13",
+    "postcss-import": "^11.0.0",
+    "postcss-loader": "^2.0.8",
+    "postcss-url": "^7.2.1",
+    "rimraf": "^2.6.0",
+    "semver": "^5.3.0",
+    "shelljs": "^0.7.6",
+    "uglifyjs-webpack-plugin": "^1.1.1",
+    "url-loader": "^0.5.8",
+    "vue-loader": "^13.3.0",
+    "vue-style-loader": "^3.0.1",
+    "vue-template-compiler": "^2.5.2",
+    "webpack": "^3.6.0",
+    "webpack-bundle-analyzer": "^2.9.0",
+    "webpack-dev-server": "^2.9.1",
+    "webpack-merge": "^4.1.0"
+  },
+  "engines": {
+    "node": ">= 6.0.0",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
+}

+ 22 - 0
src/App.vue

@@ -0,0 +1,22 @@
+<template>
+  <div id="app">
+    <router-view></router-view>
+  </div>
+</template>
+
+<script>
+import '@/assets/style/reset.less'
+import '@/assets/style/public.less'
+export default {
+  components:{
+  },
+  name: 'App'
+}
+</script>
+
+<style lang="less" scoped>
+#app {
+  width: 100%;
+  height: 100%;
+}
+</style>

BIN
src/assets/images/activity-title.png


BIN
src/assets/images/activity-type-top-bg.png


BIN
src/assets/images/arrow.png


BIN
src/assets/images/back.png


BIN
src/assets/images/close.png


BIN
src/assets/images/collection-title.png


BIN
src/assets/images/collection-type-top-bg.png


BIN
src/assets/images/exhibition-hot-hover.jpg


BIN
src/assets/images/exhibition-hot.jpg


BIN
src/assets/images/exhibition-preview-hover.jpg


BIN
src/assets/images/exhibition-preview.jpg


BIN
src/assets/images/exhibition-review-hover.jpg


BIN
src/assets/images/exhibition-review.jpg


BIN
src/assets/images/exhibition-right-arrow.png


BIN
src/assets/images/exhibition-title.png


BIN
src/assets/images/exhibition-type-top-bg.png


BIN
src/assets/images/header-bg.png


BIN
src/assets/images/home-slice-1.jpg


BIN
src/assets/images/information-activity-hover.jpg


BIN
src/assets/images/information-activity.jpg


BIN
src/assets/images/information-book-hover.jpg


BIN
src/assets/images/information-book.jpg


BIN
src/assets/images/information-infor-hover.jpg


BIN
src/assets/images/information-infor.jpg


BIN
src/assets/images/information-recentNews-hover.jpg


BIN
src/assets/images/information-recentNews.jpg


BIN
src/assets/images/information-title.png


BIN
src/assets/images/information-type-top-bg.png


BIN
src/assets/images/logo.png


BIN
src/assets/images/message-icon.png


BIN
src/assets/images/nav-logo.png


BIN
src/assets/images/paging-next.png


BIN
src/assets/images/paging-prev.png


BIN
src/assets/images/question-error.png


BIN
src/assets/images/question-tip-bg.png


BIN
src/assets/images/service-title.png


BIN
src/assets/images/service-type-top-bg.png


BIN
src/assets/images/survey-bg.png


BIN
src/assets/images/survey-con-li-bg.png


BIN
src/assets/images/survey-con-li-hover-bg.png


BIN
src/assets/images/survey-history-hover.jpg


BIN
src/assets/images/survey-history.jpg


BIN
src/assets/images/survey-introduce.png


BIN
src/assets/images/survey-introduction-hover.jpg


BIN
src/assets/images/survey-introduction.jpg


BIN
src/assets/images/survey-mechanism-hover.jpg


BIN
src/assets/images/survey-mechanism.jpg


BIN
src/assets/images/survey-mechanism.png


BIN
src/assets/images/survey-title.png


BIN
src/assets/images/survey-type-bottom-bg.png


BIN
src/assets/images/survey-type-con-bg.png


BIN
src/assets/images/survey-type-nav-bg.png


BIN
src/assets/images/survey-type-top-bg.png


BIN
src/assets/images/test-book.png


BIN
src/assets/images/test-exhibition.png


BIN
src/assets/images/test-survey-intr-pic.png


BIN
src/assets/logo.png


+ 9 - 0
src/assets/style/public.less

@@ -0,0 +1,9 @@
+html{
+    background: #fff;
+    font-family: 'Microsoft YaHei';
+  }
+*{
+  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+  tap-highlight-color: rgba(0, 0, 0, 0);
+  font-size: 16px;
+}

+ 40 - 0
src/assets/style/reset.less

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

+ 6 - 0
src/common/common.js

@@ -0,0 +1,6 @@
+export const checkPhone = function (phone){ 
+    if(!(/^1[3456789]\d{9}$/.test(phone))){ 
+        return false; 
+    }
+    return true; 
+}

+ 0 - 0
src/common/data.js


+ 73 - 0
src/common/http.js

@@ -0,0 +1,73 @@
+import axios from 'axios'
+
+var isProduction = process.env.NODE_ENV === 'production'
+
+const serverName = isProduction ? 'http://192.168.0.135:8001/' : 'http://192.168.0.135:8001/'
+// const serverName = isProduction ? 'http://8.135.106.227:8001/' : 'http://8.135.106.227:8001/'
+
+axios.defaults.baseURL = serverName
+axios.defaults.headers['X-Requested-with'] = 'XMLHttpRequest'
+// axios.defaults.headers['token'] = window.localStorage.getItem('token')
+
+axios.interceptors.request.use(function (config) {
+    if (config.method === 'post') {
+        config.data = {
+            ...config.data,
+            rnd: Math.random()
+        }
+    } else if (config.method === 'get') {
+        config.params = {
+            rnd: Math.random(),
+            ...config.params
+        }
+    }
+
+    return config
+}, function (error) {
+    // 对请求错误做些什么
+    return Promise.reject(error)
+})
+
+// 配置response拦截器
+axios.interceptors.response.use(
+    response => {
+        let data = response.data
+        let code = Number(response.data.code)
+        switch (code) {
+            case -1:
+                break
+            case 4500:
+                break
+            case 5001:
+                console.log('50015001500150015001')
+                break
+            case 5002:
+                break
+            case 500:
+                break
+            case 0:
+                break
+            default:
+                alert(data.msg)
+                break
+        }
+        return data
+    },
+    error => {
+        if (error.response) {
+            switch (error.response.status) {
+                case 400:
+                    console.log('=======前端参数传错了======')
+                    break
+                case 500:
+                    console.log('========服务器错误=======')
+                    break
+                default:
+                    console.log('error.response', error.response)
+                    break
+            }
+        }
+        return Promise.reject(error)
+    }
+)
+export { axios }

+ 27 - 0
src/components/HelloWorld.vue

@@ -0,0 +1,27 @@
+<template>
+  <div class="hello">
+    <h1>{{ msg }}</h1>
+    <h2>Essential Links</h2>
+    <button @click="toIndex()">去到index页面</button>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "HelloWorld",
+  data() {
+    return {
+      msg: "Welcome to Your Vue.js App"
+    };
+  },
+  methods: {
+    toIndex() {
+      this.$router.push({ path: "/index" });
+    },
+  },
+};
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style lang="less" scoped>
+</style>

+ 186 - 0
src/components/pagination/index.vue

@@ -0,0 +1,186 @@
+<template>
+  <div class="layer">
+    <!-- <span class="total">共{{total}}条</span> -->
+
+    <div class="number">
+      <span class="arrow" @click="current = current - 1"
+        ><img
+          class="pagejiantou"
+          :src="require(`@/assets/images/paging-prev.png`)"
+          alt=""
+      /></span>
+
+      <template v-if="currMin > min">
+        <span @click="current = min">{{ min }}</span>
+        <span v-if="currMin - 1 > min">…</span>
+      </template>
+
+      <span
+        v-for="index in numbers"
+        :key="index"
+        :class="{ active: index === current }"
+        @click="current = index"
+      >
+        {{ index }}
+      </span>
+
+      <template v-if="currMax < max">
+        <span v-if="currMax + 1 < max">…</span>
+        <span @click="current = max">{{ max }}</span>
+      </template>
+
+      <span class="arrow" @click="current = current + 1"
+        ><img
+          class="pagejiantou"
+          :src="require(`@/assets/images/paging-next.png`)"
+          alt=""
+      /></span>
+    </div>
+
+    <div v-if="false">
+      <span>前往</span>
+      <input
+        type="text"
+        :value="current"
+        @blur="(ev) => (ev.target.value = current)"
+        @keyup.enter="(ev) => (current = Number(ev.target.value))"
+      />
+      <span>页</span>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: ["paging"],
+  data() {
+    return {
+      ...this.paging,
+    };
+  },
+  computed: {
+    min() {
+      return 1;
+    },
+    max() {
+      return Math.ceil(this.total / this.pageSize);
+    },
+    routineMin() {
+      return this.current - Math.ceil(this.showSize / 2);
+    },
+    routineMax() {
+      return this.current + Math.floor(this.showSize / 2);
+    },
+    currMin() {
+      let c = this.max - this.routineMax;
+
+      if (this.routineMin <= this.min) {
+        return this.min;
+      } else if (c >= 0) {
+        return this.routineMin;
+      } else if (this.routineMin + c <= this.min) {
+        return this.min;
+      } else {
+        return this.routineMin + c;
+      }
+    },
+    currMax() {
+      let c = this.min - this.routineMin;
+
+      if (this.routineMax >= this.max) {
+        return this.max;
+      } else if (c <= 0) {
+        return this.routineMax;
+      } else if (this.routineMax + c >= this.max) {
+        return this.max;
+      } else {
+        return this.routineMax + c;
+      }
+    },
+    numbers() {
+      let total = this.currMax - this.currMin;
+      let numbers = [];
+
+      if (total === 0) {
+        numbers.push(1);
+      } else {
+        for (let i = 0; i <= total; i++) {
+          numbers.push(this.currMin + i);
+        }
+      }
+      return numbers;
+    },
+  },
+  watch: {
+    current(val, old) {
+      if (isNaN(this.current)) {
+        return (this.current = old);
+      } else if (this.current < this.min) {
+        return (this.current = this.min);
+      } else if (this.current > this.max) {
+        return (this.current = this.max);
+      }
+      this.$emit("changeCurrent", this.current);
+    },
+    paging: {
+      deep: true,
+      handler: function (newVal) {
+        Object.keys(newVal).forEach((k) => (this[k] = newVal[k]));
+      },
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.layer {
+  span {
+    font-size: 14px;
+    color: rgba(0, 0, 0, 1);
+    display: inline-block;
+    vertical-align: middle;
+    margin: 0 10px;
+    padding: 7px;
+    &.active {
+      background: linear-gradient(
+        90deg,
+        rgba(88, 90, 90, 1),
+        rgba(148, 145, 152, 1)
+      );
+      font-size: 12px;
+      font-family: Arial;
+      font-weight: bold;
+      line-height: 14px;
+      color: #ffffff;
+      opacity: 1;
+    }
+  }
+  .pagejiantou {
+    width: 10px;
+    transform: translateY(-2px);
+    cursor: pointer;
+  }
+
+  .number span {
+    margin: 0 5px;
+    cursor: pointer;
+  }
+  .number .arrow {
+      margin-top:3px;
+  }
+  div {
+    display: inline-block;
+  }
+
+  div input {
+    background: none;
+    border: 1px solid rgba(85, 85, 85, 1);
+    width: 46px;
+    height: 28px;
+    border-radius: 2px;
+    vertical-align: middle;
+    text-align: center;
+    color: #fff;
+  }
+}
+</style>

+ 49 - 0
src/main.js

@@ -0,0 +1,49 @@
+// The Vue build version to load with the `import` command
+// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
+import Vue from 'vue'
+import App from './App'
+
+import router from './router'
+
+import ElementUI from 'element-ui';
+import 'element-ui/lib/theme-chalk/index.css';
+
+import { axios } from '@/common/http'
+
+Vue.use(ElementUI);
+
+Vue.prototype.$http = axios
+
+Vue.prototype.$cdnUrl = "https://oss-xiaoan.oss-cn-shenzhen.aliyuncs.com/"
+
+Vue.config.productionTip = false
+
+import { format } from 'date-fns'
+
+// 将 yyyy-MM-yy 变成 yyyy年mm月dd日
+Vue.filter('dateFormat', function (value, formatStr = 'yyyy-MM-yy HH:mm:ss') {
+  value = new Date(value)
+  let newVale = format(value, formatStr);
+  // let reg =/(\d{4})\-(\d{2})\-(\d{2})/; newVale.replace(reg,"$1年$2月$3日")
+  return newVale
+})
+Vue.filter('dateFormat1', function (value, formatStr = 'yyyy-MM-yy HH:mm:ss') {
+  value = new Date(value)
+  let newVale = format(value, formatStr);
+  let reg =/(\d{4})\-(\d{2})\-(\d{2})/; 
+  return newVale.replace(reg,"$1年$2月$3日")
+})
+Vue.filter('dateFormat2', function (value, formatStr = 'yyyy-MM-yy HH:mm:ss') {
+  value = new Date(value)
+  let newVale = format(value, formatStr);
+  let reg =/(\d{4})\-(\d{2})\-(\d{2})/; 
+  return newVale.replace(reg,"$1年$2月$3日").slice(5)
+})
+
+/* eslint-disable no-new */
+new Vue({
+  el: '#app',
+  router,
+  components: { App },
+  template: '<App/>'
+})

+ 331 - 0
src/pages/activity/activity-detail.vue

@@ -0,0 +1,331 @@
+<!--  -->
+<template>
+  <div class="activity-detail">
+    <div class="wrapper">
+      <div class="top">
+        <img
+          class="bg"
+          :src="require('@/assets/images/information-type-top-bg.png')"
+          alt=""
+        />
+      </div>
+      <div class="bottom">
+        <img
+          class="bg"
+          :src="require('@/assets/images/survey-type-bottom-bg.png')"
+          alt=""
+        />
+
+        <div class="content">
+          <div class="nav">
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-nav-bg.png')"
+              alt=""
+            />
+            <div class="nav-con">
+              <div class="nav-con-title">活动</div>
+              <div class="nav-con-type">
+                <ul>
+                  <li
+                    :class="{ cur: activityType === 'onLine' }"
+                    @click="switchType('onLine')"
+                  >
+                    <a>线上活动</a>
+                    <div class="arrow" v-if="activityType === 'onLine'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                  <li
+                    :class="{ cur: activityType === 'volunteer' }"
+                    @click="switchType('volunteer')"
+                  >
+                    <a>志愿者服务</a>
+                    <div class="arrow" v-if="activityType === 'volunteer'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                  <li
+                    :class="{ cur: activityType === 'satisfaction' }"
+                    @click="switchType('satisfaction')"
+                  >
+                    <a>满意度调查</a>
+                    <div class="arrow" v-if="activityType === 'satisfaction'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                </ul>
+              </div>
+            </div>
+          </div>
+          <div class="con">
+            <div class="back" @click="back">
+              <img :src="require('@/assets/images/back.png')" alt="" />
+            </div>
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-con-bg.png')"
+              alt=""
+            />
+            <div class="detail">
+              <div class="detail-wrapper">
+                <div class="detail-title">{{ detail.name }}</div>
+                <div class="detail-desc">
+                  <span
+                    >发布时间:&nbsp;{{ detail.createTime }}&nbsp;&nbsp;</span
+                  >
+                  <span>分类:&nbsp;{{ detail.type === 'online'? '线上活动': detail.type === 'volunteer'? '志愿者服务':'' }}</span>
+                </div>
+                <div class="detail-con" v-html="detail.content"></div>
+              </div>
+              <!-- <div class="bottom-nav">
+                <div class="bottom-nav-left">
+                  <img
+                    :src="require('@/assets/images/paging-prev.png')"
+                    alt=""
+                  />
+                  <a class="prev-title">上一篇&nbsp;&nbsp;标题标题</a>
+                </div>
+                <div class="bottom-nav-right">
+                  <a class="next-title">下一篇&nbsp;&nbsp;标题标题</a>
+                  <img
+                    :src="require('@/assets/images/paging-next.png')"
+                    alt=""
+                  />
+                </div>
+              </div> -->
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+//例如:import 《组件名称》 from '《组件路径》';
+import Paging from "@/components/pagination";
+export default {
+  name: "survey",
+  //import引入的组件需要注入到对象中才能使用
+  components: {
+    Paging,
+  },
+  data() {
+    //这里存放数据
+    return {
+      activityType: "onLine",
+      detail: {},
+    };
+  },
+  //监听属性 类似于data概念
+  computed: {},
+  //监控data中的数据变化
+  watch: {},
+  //方法集合
+  methods: {
+    switchType(type) {
+      this.$router.push({ path: "/activity-type", query: { type } });
+    },
+    back() {
+      this.$router.push({
+        path: "/activity-type",
+        query: { type: this.detail.navType || "" },
+      });
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    // console.log("this.$route.query", this.$route.query);
+    this.detail = this.$route.query;
+    this.activityType = this.detail.navType;
+    console.log('this.detail',this.detail)
+    // console.log("this.detail", this.detail);
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='less' scoped>
+.bg {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  left: 0;
+  top: 0;
+  z-index: -1;
+}
+.activity-detail {
+  width: 100%;
+  margin-bottom: 98px;
+  .wrapper {
+    width: 100%;
+    .top {
+      width: 100%;
+      height: 278px;
+      position: relative;
+    }
+    .bottom {
+      width: 100%;
+      position: relative;
+      .content {
+        min-width: 1090px;
+        margin: 0 auto;
+        width: 57%;
+        display: flex;
+        justify-content: center;
+        .nav {
+          flex: 1;
+          margin-right: 1%;
+          margin-top: -68px;
+          position: relative;
+          .nav-con {
+            width: 85%;
+            margin: 94px auto 0;
+            .nav-con-title {
+              background: #a01c26ff;
+              padding: 14.5px 0 14.5px 46px;
+              font-size: 20px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #ffffff;
+              opacity: 1;
+            }
+            .nav-con-type {
+              margin-top: 3px;
+              background: rgba(160, 28, 38, 0.6);
+              overflow: hidden;
+              > ul {
+                width: 100%;
+                margin-top: 21px;
+                margin-bottom: 105px;
+                > li {
+                  width: 100%;
+                  padding: 8px 0 8px 51px;
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #000000;
+                  position: relative;
+                  cursor: pointer;
+                  .arrow {
+                    position: absolute;
+                    top: 10px;
+                    right: 11.5px;
+                    width: 10.5px;
+                    height: 18px;
+                    > img {
+                      width: 100%;
+                      height: 100%;
+                    }
+                  }
+                }
+                .cur {
+                  background: linear-gradient(180deg, #585a5a 0%, #949198 100%);
+                  color: #ffffff;
+                }
+              }
+            }
+          }
+        }
+        .con {
+          flex: 3;
+          margin-top: -68px;
+          position: relative;
+          .back {
+            width: 19px;
+            position: absolute;
+            left: 26px;
+            top: 97px;
+            cursor: pointer;
+            > img {
+              width: 100%;
+            }
+          }
+          .detail {
+            width: 100%;
+            .detail-wrapper {
+              font-family: Microsoft YaHei;
+              color: #202020;
+              line-height: 24px;
+              width: 86%;
+              margin: 152px auto 80px;
+              max-width: 708px;
+              overflow-x: scroll;
+              .detail-title {
+                text-align: center;
+                font-size: 18px;
+                font-weight: bold;
+              }
+              .detail-desc {
+                text-align: center;
+                margin-top: 8px;
+                font-size: 12px;
+                font-weight: 400;
+              }
+              .detail-con {
+                margin-top: 32px;
+              }
+            }
+            .bottom-nav {
+              width: 100%;
+              display: flex;
+              justify-content: space-between;
+              height: 61px;
+              line-height: 61px;
+              .bottom-nav-left,
+              .bottom-nav-right {
+                cursor: pointer;  
+                overflow: hidden;
+                > img {
+                  width: 16px;
+                  vertical-align: middle;
+                }
+                > a {
+                  vertical-align: middle;
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: bold;
+                  line-height: 21px;
+                  color: #000000;
+                  opacity: 0.8;
+                }
+              }
+              .bottom-nav-left {
+                  margin-left: 64px;
+                  > img {
+                      margin-right: 10px;
+                  }
+                  &:hover {
+                      >a {
+                          color:rgba(160, 28, 38, 1);
+                      }
+                  }
+              }
+              .bottom-nav-right {
+                  margin-right: 64px;
+                  > img {
+                      margin-left: 10px;
+                  }
+                  &:hover {
+                      >a {
+                          color:rgba(160, 28, 38, 1);
+                      }
+                  }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 883 - 0
src/pages/activity/activity-type.vue

@@ -0,0 +1,883 @@
+<!--  -->
+<template>
+  <div class="activity-type">
+    <div class="wrapper">
+      <div class="top">
+        <img
+          class="bg"
+          :src="require('@/assets/images/activity-type-top-bg.png')"
+          alt=""
+        />
+      </div>
+      <div class="bottom">
+        <img
+          class="bg"
+          :src="require('@/assets/images/survey-type-bottom-bg.png')"
+          alt=""
+        />
+
+        <div class="content">
+          <div class="nav">
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-nav-bg.png')"
+              alt=""
+            />
+            <div class="nav-con">
+              <div class="nav-con-title">活动</div>
+              <div class="nav-con-type">
+                <ul>
+                  <li
+                    :class="{ cur: activityType === 'onLine' }"
+                    @click="switchType('onLine')"
+                  >
+                    <a>线上活动</a>
+                    <div class="arrow" v-if="activityType === 'onLine'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                  <li
+                    :class="{ cur: activityType === 'volunteer' }"
+                    @click="switchType('volunteer')"
+                  >
+                    <a>志愿者服务</a>
+                    <div class="arrow" v-if="activityType === 'volunteer'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                  <li
+                    :class="{ cur: activityType === 'satisfaction' }"
+                    @click="switchType('satisfaction')"
+                  >
+                    <a>满意度调查</a>
+                    <div class="arrow" v-if="activityType === 'satisfaction'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                </ul>
+              </div>
+            </div>
+            <div class="questionCard" v-show="activityType === 'satisfaction'">
+              <div class="card">
+                <ul>
+                  <div class="ques-title">题目</div>
+                  <li
+                    v-for="(question, index) in questionnaireList"
+                    :key="index"
+                    :class="{
+                      selected:
+                        question.type === 'single'
+                          ? !!question.answer
+                          : !!question.answer && question.answer.length,
+                    }"
+                  >
+                  <!-- :href="`/#/activity-type/#${question.id}?type=satisfaction`" -->
+                    <a>
+                      {{ index + 1 }}
+                    </a>
+                  </li>
+                </ul>
+              </div>
+              <div class="information">
+                <div class="information-con">
+                  <div class="inf-name">
+                    <span>填写姓名</span>
+                    <input
+                      type="text"
+                      v-model="name"
+                      placeholder="请输入姓名"
+                    />
+                  </div>
+                  <div class="inf-phone">
+                    <span>手机号</span>
+                    <input
+                      type="text"
+                      v-model="phone"
+                      placeholder="请输入手机号码"
+                    />
+                  </div>
+                  <div class="inf-btn" @click="save()">提交</div>
+                </div>
+                <div class="information-errTip" v-if="questionComplete">
+                  <img
+                    class="tip-bg"
+                    :src="require('@/assets/images/question-tip-bg.png')"
+                    alt=""
+                  />
+                  <img
+                    class="tip-close"
+                    @click="questionComplete = false"
+                    :src="require('@/assets/images/close.png')"
+                    alt=""
+                  />
+                  <img
+                    class="tip-icon"
+                    :src="require('@/assets/images/question-error.png')"
+                    alt=""
+                  />
+                  <div class="tip-txt">问卷未填写完整!</div>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="con">
+            <!-- <div class="back" @click="back">
+              <img :src="require('@/assets/images/back.png')" alt="" />
+            </div> -->
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-con-bg.png')"
+              alt=""
+            />
+            <div
+              class="list"
+              v-show="activityType === 'onLine' || activityType === 'volunteer'"
+            >
+              <ul>
+                <li
+                  v-for="(item, index) in dataList"
+                  :key="index"
+                  @click="toDetail(item)"
+                >
+                  <div class="desc">
+                    <div class="desc-title">{{ item.name || "--" }}</div>
+                    <div class="desc-time">{{ item.createTime || "--" }}</div>
+                  </div>
+                </li>
+              </ul>
+              <el-empty :image-size="200" v-if="dataList.length === 0"></el-empty>
+              <div class="my-paging" v-if="dataList.length">
+                <Paging
+                  v-if="paging.total"
+                  :paging="paging"
+                  @changeCurrent="pageChange"
+                />
+              </div>
+            </div>
+            <!-- 问卷调查 -->
+            <div class="satisfaction" v-show="activityType === 'satisfaction'">
+              <div class="s-title">大理市博物馆观众调查问卷</div>
+              <div class="s-des">
+                为了更好地发挥大理市博物馆在宣传展示和社会服务方面的作用,我们希望能够通过您对这些问题的回答,提高我们的工作质量,我们会认真考虑您的意见和建议。非常感谢您对我们工作的配合和支持!
+              </div>
+              <ul>
+                <li v-for="(question, index) in questionnaireList" :key="index">
+                  <div class="line"></div>
+                  <div class="question">
+                    <div class="q-title">
+                      {{ index + 1 }}. {{ question.title
+                      }}{{ question.type === "multiple" ? `(可多选)` : `` }}:
+                      <span
+                        v-if="question.type === 'multiple'"
+                        v-html="`<br>`"
+                      ></span>
+                    </div>
+                    <ul class="q-answer">
+                      <!-- 单选 -->
+                      <div class="single" v-if="question.type === 'single'">
+                        <li
+                          v-for="(choose, optionIndex) in question.chooseList"
+                          :key="optionIndex"
+                        >
+                        <!-- :id="`${question.id}`" -->
+                          <a>
+                            <input
+                              type="radio"
+                              v-model="question.answer"
+                              :value="choose"
+                            />
+                            <label>{{ choose }}</label>
+                          </a>
+                        </li>
+                      </div>
+                      <!-- 多选题 -->
+                      <ul class="multiple" v-if="question.type === 'multiple'">
+                        <li
+                          v-for="(choose, optionIndex) in question.chooseList"
+                          :key="optionIndex"
+                        >
+                        <!-- :id="`${question.id}`" -->
+                          <a>
+                            <input
+                              type="checkbox"
+                              :value="choose"
+                              v-model="question.answer"
+                            />
+                            <label>{{ choose }}</label>
+                          </a>
+                        </li>
+                      </ul>
+                    </ul>
+                  </div>
+                </li>
+              </ul>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+//例如:import 《组件名称》 from '《组件路径》';
+import Paging from "@/components/pagination";
+import { checkPhone } from "@/common/common.js";
+export default {
+  name: "survey",
+  //import引入的组件需要注入到对象中才能使用
+  components: {
+    Paging,
+  },
+  data() {
+    //这里存放数据
+    return {
+      activityType: "onLine",
+      dataList: [],
+      paging: {
+        pageSize: 10,
+        pageNum: 1,
+        total: 0,
+        showSize: 10,
+        current: 1,
+      },
+      params: {
+        pageNum: 1,
+        pageSize: 10,
+        type: "",
+      },
+      typeChange: {
+        onLine: "online",
+        volunteer: "volunteer",
+      },
+      questionnaireList: [
+        {
+          id: 0,
+          title: "问题1问题1问题1问题1问题1问题1问题1",
+          type: "single",
+          chooseList: [
+            "选项1",
+            "选项2",
+            "选项3",
+            "选项4",
+            "选项5",
+            "选项6",
+            "选项7",
+            "选项8",
+          ],
+        },
+        {
+          id: 1,
+          title: "问题2问题2问题2问题2问题2问题2问题2",
+          type: "single",
+          chooseList: ["选项1", "选项2", "选项3", "选项4"],
+        },
+        {
+          id: 2,
+          title: "多选1多选1多选1多选1多选1多选1多选1",
+          type: "multiple",
+          chooseList: [
+            "选项1",
+            "选项2",
+            "选项3",
+            "选项4",
+            "选项5",
+            "选项6",
+            "选项7",
+            "选项8",
+            "选项9",
+            "选项10",
+            "选项11",
+            "选项12",
+            "选项13",
+          ],
+          answer: [],
+        },
+        {
+          id: 3,
+          title: "多选2多选2多选2多选2多选2多选2多选2",
+          type: "multiple",
+          chooseList: ["选项1", "选项2", "选项3", "选项4"],
+          answer: [],
+        },
+        {
+          id: 5,
+          title: "多选2多选2多选2多选2多选2多选2多选2",
+          type: "multiple",
+          chooseList: ["选项1", "选项2", "选项3", "选项4"],
+          answer: [],
+        },
+        {
+          id: 6,
+          title: "多选2多选2多选2多选2多选2多选2多选2",
+          type: "multiple",
+          chooseList: ["选项1", "选项2", "选项3", "选项4"],
+          answer: [],
+        },
+        {
+          id: 7,
+          title: "多选1多选1多选1多选1多选1多选1多选1",
+          type: "multiple",
+          chooseList: ["选项1", "选项2", "选项3", "选项4"],
+          answer: [],
+        },
+        {
+          id: 8,
+          title: "多选1多选1多选1多选1多选1多选1多选1",
+          type: "multiple",
+          chooseList: ["选项1", "选项2", "选项3", "选项4"],
+          answer: [],
+        },
+        {
+          id: 9,
+          title: "多选2多选2多选2多选2多选2多选2多选2",
+          type: "multiple",
+          chooseList: ["选项1", "选项2", "选项3", "选项4"],
+          answer: [],
+        },
+        {
+          id: 10,
+          title: "多选2多选2多选2多选2多选2多选2多选2",
+          type: "multiple",
+          chooseList: ["选项1", "选项2", "选项3", "选项4"],
+          answer: [],
+        },
+        {
+          id: 11,
+          title: "多选2多选2多选2多选2多选2多选2多选2",
+          type: "single",
+          chooseList: ["选项1", "选项2", "选项3", "选项4"],
+          answer: "",
+        },
+        {
+          id: 12,
+          title: "多选2多选2多选2多选2多选2多选2多选2",
+          type: "multiple",
+          chooseList: ["选项1", "选项2", "选项3", "选项4"],
+          answer: [],
+        },
+        {
+          id: 13,
+          title: "多选2多选2多选2多选2多选2多选2多选2",
+          type: "multiple",
+          chooseList: ["选项1", "选项2", "选项3", "选项4"],
+          answer: [],
+        },
+      ],
+      name: "",
+      phone: "",
+      questionComplete: false,
+    };
+  },
+  //监听属性 类似于data概念
+  computed: {},
+  //监控data中的数据变化
+  watch: {
+    paging: {
+      deep: true,
+      handler: function () {},
+    },
+  },
+  //方法集合
+  methods: {
+    async getList() {
+      let result = await this.$http({
+        method: "post",
+        url: "/api/web/activity/list",
+        data: this.params,
+      });
+      this.dataList = result.data.list;
+      this.paging.total = result.data.total;
+    },
+    switchType(type) {
+      this.activityType = type;
+      this.params["type"] = this.typeChange[this.activityType];
+      this.params["pageNum"] = 1;
+      this.paging.current = 1;
+      if (type != "satisfaction") {
+        this.getList();
+      }
+    },
+    back() {
+      this.$router.push({ path: "/activity" });
+    },
+    pageChange(val) {
+      console.log(val);
+      this.paging.current = val;
+      this.params.pageNum = val;
+      this.getList();
+    },
+    toDetail(item) {
+      this.$router.push({
+        path: "/activity-detail",
+        query: { ...item, navType: this.activityType },
+      });
+    },
+    save() {
+      console.log("this.questionnaireList", this.questionnaireList);
+      this.questionnaireList.forEach((item) => {
+        if (item.type === "single" && !item.answer) {
+          this.questionComplete = true;
+        }
+        if (
+          (item.type === "mutiple" && !item.answer) ||
+          (!!item.answer && item.answer.length === 0)
+        ) {
+          this.questionComplete = true;
+        }
+      });
+      if (this.questionComplete === true) return;
+      if (!this.name) {
+        window.alert("请输入姓名");
+        return;
+      }
+      if (!this.phone) {
+        window.alert("请输入手机号码");
+        return;
+      }
+      if (!checkPhone(this.phone)) {
+        window.alert("请输入正确的手机号码");
+        return;
+      }
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    this.activityType =
+      (this.$route.query && this.$route.query["type"]) || "onLine";
+    this.params["type"] = this.typeChange[this.activityType];
+    if (!this.params["type"]) return;
+    this.getList();
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='less' scoped>
+.bg {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  left: 0;
+  top: 0;
+  z-index: -1;
+}
+.activity-type {
+  width: 100%;
+  margin-bottom: 98px;
+  .wrapper {
+    width: 100%;
+    .top {
+      width: 100%;
+      height: 278px;
+      position: relative;
+    }
+    .bottom {
+      width: 100%;
+      position: relative;
+      .content {
+        min-width: 1090px;
+        margin: 0 auto;
+        width: 57%;
+        display: flex;
+        justify-content: center;
+        .nav {
+          flex: 1;
+          margin-right: 1%;
+          margin-top: -68px;
+          position: relative;
+          .nav-con {
+            width: 85%;
+            margin: 94px auto 0;
+            .nav-con-title {
+              background: #a01c26ff;
+              padding: 14.5px 0 14.5px 46px;
+              font-size: 20px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #ffffff;
+              opacity: 1;
+            }
+            .nav-con-type {
+              margin-top: 3px;
+              background: rgba(160, 28, 38, 0.6);
+              overflow: hidden;
+              > ul {
+                width: 100%;
+                margin-top: 21px;
+                margin-bottom: 105px;
+                > li {
+                  width: 100%;
+                  padding: 8px 0 8px 51px;
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #000000;
+                  position: relative;
+                  cursor: pointer;
+                  .arrow {
+                    position: absolute;
+                    top: 10px;
+                    right: 11.5px;
+                    width: 10.5px;
+                    height: 18px;
+                    > img {
+                      width: 100%;
+                      height: 100%;
+                    }
+                  }
+                }
+                .cur {
+                  background: linear-gradient(180deg, #585a5a 0%, #949198 100%);
+                  color: #ffffff;
+                }
+              }
+            }
+          }
+          .questionCard {
+            width: 85%;
+            margin: 0 auto;
+            background: rgba(255, 255, 255, 0.9);
+            padding: 12px;
+            .card {
+              width: 100%;
+              > ul {
+                width: 100%;
+                border: 1px solid rgba(148, 145, 152, 0.38);
+                border-radius: 4px;
+                box-sizing: content-box;
+                .ques-title {
+                  display: inline-block;
+                  width: 64px;
+                  height: 35px;
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  line-height: 35px;
+                  text-align: center;
+                  color: #ffffff;
+                  background: linear-gradient(180deg, #585a5a 0%, #949198 100%);
+                  border-radius: 4px 0px 4px 0px;
+                  opacity: 1;
+                }
+                > li {
+                  display: inline-block;
+                  width: 22px;
+                  height: 22px;
+                  background: rgba(148, 145, 152, 0.47);
+                  border-radius: 50%;
+                  text-align: center;
+                  margin: 6px;
+                  cursor: pointer;
+                  line-height: 18px;
+                  > a {
+                    font-size: 12px;
+                    font-family: Microsoft YaHei;
+                    font-weight: 400;
+                    color: #ffffff;
+                  }
+                }
+                li.selected {
+                  background: #a01c26;
+                }
+              }
+            }
+            .information {
+              width: 100%;
+              position: relative;
+              .information-con {
+                width: 100%;
+                border: 1px solid rgba(148, 145, 152, 0.38);
+                border-radius: 4px;
+                margin-top: 7px;
+                .inf-name,
+                .inf-phone {
+                  width: 90%;
+                  margin: 0 auto;
+                  margin-top: 22px;
+                  display: flex;
+                  > span {
+                    display: inline-block;
+                    width: 40%;
+                    height: 30px;
+                    line-height: 30px;
+                    background: rgba(32, 32, 32, 0.5);
+                    text-align: center;
+                    font-size: 14px;
+                    font-family: Microsoft YaHei;
+                    font-weight: 300;
+                    color: #ffffff;
+                    border-radius: 4px 0 0 4px;
+                  }
+                  > input {
+                    width: 60%;
+                    height: 30px;
+                    display: inline-block;
+                    border: 1px solid rgba(148, 145, 152, 0.38);
+                    border-radius: 0 4px 4px 0;
+                    padding-left: 8px;
+                    &::placeholder {
+                      font-size: 14px;
+                      font-family: Microsoft YaHei;
+                      font-weight: 400;
+                      color: #949198;
+                      opacity: 0.61;
+                    }
+                  }
+                }
+                .inf-phone {
+                  width: 90%;
+                  margin: 0 auto;
+                  width: 90%;
+                  margin-top: 22px;
+                }
+                .inf-btn {
+                  width: 60%;
+                  margin: 22px auto;
+                  height: 30px;
+                  text-align: center;
+                  line-height: 30px;
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #ffffff;
+                  background: #a01c26;
+                  border-radius: 4px;
+                  cursor: pointer;
+                }
+              }
+              .information-errTip {
+                width: 100%;
+                height: 100%;
+                position: absolute;
+                left: 0;
+                top: 0;
+                .tip-close {
+                  width: 13px;
+                  position: absolute;
+                  right: 8px;
+                  top: 18px;
+                  cursor: pointer;
+                }
+                .tip-bg {
+                  width: 100%;
+                }
+                .tip-icon {
+                  width: 22%;
+                  position: absolute;
+                  left: 50%;
+                  top: 48px;
+                  transform: translateX(-50%);
+                }
+                .tip-txt {
+                  width: 100%;
+                  position: absolute;
+                  left: 0;
+                  top: 95px;
+                  text-align: center;
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  line-height: 40px;
+                  color: #ffffff;
+                  opacity: 1;
+                }
+              }
+            }
+          }
+        }
+        .con {
+          flex: 3;
+          margin-top: -68px;
+          position: relative;
+          .back {
+            width: 19px;
+            position: absolute;
+            left: 26px;
+            top: 97px;
+            cursor: pointer;
+            > img {
+              width: 100%;
+            }
+          }
+          .list {
+            > ul {
+              margin: 94px 19px 38px;
+              > li {
+                background: linear-gradient(
+                  180deg,
+                  rgba(222, 222, 222, 0.6) 0%,
+                  rgba(255, 255, 255, 0.6) 100%
+                );
+                cursor: pointer;
+                border-radius: 4px;
+                display: flex;
+                justify-content: flex-start;
+                margin-bottom: 8px;
+                padding: 17px 27px;
+                &:nth-last-child(1) {
+                  margin-bottom: 0;
+                }
+                .desc {
+                  width: 100%;
+                  display: flex;
+                  justify-content: space-between;
+                  .desc-title {
+                    font-size: 20px;
+                    font-family: Microsoft YaHei;
+                    font-weight: 400;
+                    line-height: 26px;
+                    color: #202020;
+                    opacity: 1;
+                    &::before {
+                      content: "";
+                      display: inline-block;
+                      width: 6px;
+                      height: 6px;
+                      background: linear-gradient(
+                        180deg,
+                        #585a5a 0%,
+                        #949198 100%
+                      );
+                      margin-bottom: 3px;
+                      margin-right: 14px;
+                      border-radius: 50%;
+                    }
+                  }
+                  .desc-time {
+                    font-size: 18px;
+                    font-family: Microsoft YaHei;
+                    font-weight: 400;
+                    line-height: 24px;
+                    color: #202020;
+                    opacity: 0.6;
+                  }
+                }
+              }
+              > li:hover {
+                box-shadow: 0px 3px 6px rgba(0, 0, 0, 1);
+              }
+            }
+            .my-paging {
+              margin: 25px auto;
+              text-align: right;
+            }
+          }
+          .satisfaction {
+            margin: 94px 32px 95px;
+            .s-title {
+              width: 100%;
+              text-align: center;
+              font-size: 18px;
+              font-family: Arial;
+              font-weight: bold;
+              line-height: 24px;
+              color: #000000;
+            }
+            .s-des {
+              width: 100%;
+              margin-top: 25px;
+              margin-bottom: 18px;
+              font-family: Microsoft YaHei;
+              font-weight: 400;
+              line-height: 27px;
+              color: #202020;
+            }
+            > ul {
+              width: 100%;
+              li {
+                width: 100%;
+                .line {
+                  height: 4px;
+                  background: linear-gradient(
+                    90deg,
+                    rgba(88, 90, 90, 0.3),
+                    rgba(148, 145, 152, 0.3)
+                  );
+                }
+                .question {
+                  margin: 23px auto 13px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #202020;
+                  font-size: 16px;
+                  .q-title {
+                    color: rgba(160, 28, 38, 1);
+                    margin-right: 15px;
+                    display: inline;
+                  }
+                  .q-answer {
+                    display: inline;
+                    .single,
+                    .multiple {
+                      width: 100%;
+                      display: inline;
+                      > li {
+                        display: inline;
+                        margin-right: 30px;
+                        line-height: 30px;
+
+                        // > input[type="radio"] + label {
+                        //   font-size: 16px;
+                        //   font-family: Microsoft YaHei;
+                        //   font-weight: 400;
+                        //   line-height: 27px;
+                        //   color: #202020;
+                        //   opacity: 1;
+                        // }
+                        // > input[type="radio"] {
+                        //   width: 20px;
+                        //   height: 20px;
+                        // }
+                        // > input[type="radio"] + label {
+                        //   cursor: pointer;
+                        // }
+                        // > input[type="radio"] + label::before {
+                        //   content: "";
+                        //   display: inline-block;
+                        //   vertical-align: middle;
+                        //   font-size: 18px;
+                        //   width: 17px;
+                        //   height: 17px;
+                        //   margin-right: 0.4em;
+                        //   border-radius: 50%;
+                        //   border: 1px solid #949198;
+                        //   text-indent: 0.15em;
+                        //   line-height: 1;
+                        // }
+                        // > .radioCurrent + label::before {
+                        //   background-color: rgba(160, 28, 38, 1);
+                        // }
+                        // > input[type="radio"]:checked + label::before {
+                        //   background-color: rgba(160, 28, 38, 1);
+                        // }
+                        // > input[type="radio"] {
+                        //   position: absolute;
+                        //   clip: rect(0, 0, 0, 0);
+                        // }
+                      }
+                    }
+                    .multiple {
+                      width: 80%;
+                      display: block;
+                      margin: 0 auto;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 145 - 0
src/pages/activity/activity.vue

@@ -0,0 +1,145 @@
+<!--  -->
+<template>
+  <div class="survey">
+    <img class="bg" :src="require('@/assets/images/survey-bg.png')" alt="" />
+    <div class="content">
+      <div class="logo">
+        <img :src="require('@/assets/images/activity-title.png')" alt="" />
+      </div>
+      <ul>
+        <li @click="toType('onLine')" @mouseover="mouseOver('onLine')" @mouseleave="mouseLeave('onLine')">
+          <img :src="require(`@/assets/images/survey-introduction${onLineHover?'-hover':''}.jpg`)" alt="" />
+          <div class="txt">线上活动</div>
+        </li>
+        <li @click="toType('volunteer')" @mouseover="mouseOver('volunteer')" @mouseleave="mouseLeave('volunteer')" >
+          <img :src="require(`@/assets/images/survey-history${volunteerHover?'-hover':''}.jpg`)" alt="" />
+          <div class="txt">志愿者服务</div>
+        </li>
+        <li @click="toType('satisfaction')" @mouseover="mouseOver('satisfaction')" @mouseleave="mouseLeave('satisfaction')">
+          <img :src="require(`@/assets/images/survey-mechanism${satisfactionHover?'-hover':''}.jpg`)" alt="" />
+          <div class="txt">满意度调查</div>
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
+
+<script>
+//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+//例如:import 《组件名称》 from '《组件路径》';
+
+export default {
+  name: "activity",
+  //import引入的组件需要注入到对象中才能使用
+  components: {},
+  data() {
+    //这里存放数据
+    return {
+      onLineHover: false,
+      volunteerHover:false,
+      satisfactionHover:false
+    };
+  },
+  //监听属性 类似于data概念
+  computed: {},
+  //监控data中的数据变化
+  watch: {},
+  //方法集合
+  methods: {
+    toType(type) {
+      this.$router.push({path: '/activity-type', query: {type}})
+    },
+    mouseOver(type){
+      switch(type) {
+        case 'onLine':
+          this.onLineHover = true;
+          break;
+        case 'volunteer':
+          this.volunteerHover = true;
+          break;
+        case 'satisfaction':
+          this.satisfactionHover = true;
+          break;
+      }
+    },
+    mouseLeave(type){
+      switch(type) {
+        case 'onLine':
+          this.onLineHover = false;
+          break;
+        case 'volunteer':
+          this.volunteerHover = false;
+          break;
+        case 'satisfaction':
+          this.satisfactionHover = false;
+          break;
+      }
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='less' scoped>
+.survey {
+  width: 100%;
+  position: relative;
+  overflow: hidden;
+  .bg {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: -1;
+  }
+  .content {
+    margin: 66px auto 142px 464px;
+    display: flex;
+    .logo {
+      width: 120px;
+      > img {
+        width: 100%;
+      }
+    }
+    ul {
+      display: flex;
+      margin-left: 105px;
+      margin-top: 107px;
+      display: flex;
+      li {
+        width: 259px;
+        height: 624px;
+        position: relative;
+        margin-right: 23px;
+        cursor: pointer;
+        .txt {
+          width: 28px;
+          font-size: 28px;
+          font-family: Microsoft YaHei;
+          font-weight: 400;
+          line-height: 33px;
+          color: #000000;
+          opacity: 0.7;
+          position: absolute;
+          top:9px;
+          right: 20px;
+        }
+        > img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+    }
+  }
+}
+</style>

+ 269 - 0
src/pages/collection/collection-detail.vue

@@ -0,0 +1,269 @@
+<!--  -->
+<template>
+  <div class="collection-detail">
+    <div class="wrapper">
+      <div class="top">
+        <img
+          class="bg"
+          :src="require('@/assets/images/collection-type-top-bg.png')"
+          alt=""
+        />
+      </div>
+      <div class="bottom">
+        <img
+          class="bg"
+          :src="require('@/assets/images/survey-type-bottom-bg.png')"
+          alt=""
+        />
+
+        <div class="content">
+          <div class="nav">
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-nav-bg.png')"
+              alt=""
+            />
+            <div class="nav-con">
+              <div class="nav-con-title">典藏</div>
+              <div class="nav-con-type">
+                <ul>
+                  <li
+                    :class="{ cur: collectionType === 'boutique' }"
+                    @click="switchType('boutique')"
+                  >
+                    <a>精品典藏</a>
+                    <div class="arrow" v-if="collectionType === 'boutique'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                  <li
+                    :class="{ cur: collectionType === 'threeDimensional' }"
+                    @click="switchType('threeDimensional')"
+                  >
+                    <a>三维藏品</a>
+                    <div
+                      class="arrow"
+                      v-if="collectionType === 'threeDimensional'"
+                    >
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                </ul>
+              </div>
+            </div>
+          </div>
+          <div class="con">
+            <div class="back" @click="back">
+              <img :src="require('@/assets/images/back.png')" alt="" />
+            </div>
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-con-bg.png')"
+              alt=""
+            />
+            <div class="detail">
+              <div class="detail-wrapper">
+                <div class="detail-picOrModel">
+                  <img v-if="detail.type === 'img'" :src="$cdnUrl + detail.thumb" alt=""   />
+                  <iframe v-if="detail.type === 'model'" :src="detail.modelUrl" frameborder="0"></iframe>
+                </div>
+                <div class="detail-title">{{ detail.name }}</div>
+                <div class="detail-desc">
+                  <span>年代:&nbsp;{{ detail.age }}&nbsp;&nbsp;</span>
+                  <span>分类:&nbsp;{{ detail.goodsTypeId }}</span>
+                </div>
+                <div class="detail-con" v-html="detail.description"></div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+//例如:import 《组件名称》 from '《组件路径》';
+export default {
+  name: "collection-detail",
+  //import引入的组件需要注入到对象中才能使用
+  components: {},
+  data() {
+    //这里存放数据
+    return {
+      collectionType: "boutique",
+      detail: {},
+    };
+  },
+  //监听属性 类似于data概念
+  computed: {},
+  //监控data中的数据变化
+  watch: {},
+  //方法集合
+  methods: {
+    switchType(type) {
+      this.$router.push({ path: "/collection-type", query: { type } });
+    },
+    back() {
+      this.$router.push({
+        path: "/collection-type",
+        query: { type: this.detail.navType || "" },
+      });
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    this.detail = this.$route.query;
+    this.collectionType = this.detail.navType;
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='less' scoped>
+.bg {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  left: 0;
+  top: 0;
+  z-index: -1;
+}
+.collection-detail {
+  width: 100%;
+  margin-bottom: 98px;
+  .wrapper {
+    width: 100%;
+    .top {
+      width: 100%;
+      height: 278px;
+      position: relative;
+    }
+    .bottom {
+      width: 100%;
+      position: relative;
+      .content {
+        min-width: 1090px;
+        margin: 0 auto;
+        width: 57%;
+        display: flex;
+        justify-content: center;
+        .nav {
+          flex: 1;
+          margin-right: 1%;
+          margin-top: -68px;
+          position: relative;
+          .nav-con {
+            width: 85%;
+            margin: 94px auto 0;
+            .nav-con-title {
+              background: #a01c26ff;
+              padding: 14.5px 0 14.5px 46px;
+              font-size: 20px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #ffffff;
+              opacity: 1;
+            }
+            .nav-con-type {
+              margin-top: 3px;
+              background: rgba(160, 28, 38, 0.6);
+              overflow: hidden;
+              > ul {
+                width: 100%;
+                margin-top: 21px;
+                margin-bottom: 105px;
+                > li {
+                  width: 100%;
+                  padding: 8px 0 8px 51px;
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #000000;
+                  position: relative;
+                  cursor: pointer;
+                  .arrow {
+                    position: absolute;
+                    top: 10px;
+                    right: 11.5px;
+                    width: 10.5px;
+                    height: 18px;
+                    > img {
+                      width: 100%;
+                      height: 100%;
+                    }
+                  }
+                }
+                .cur {
+                  background: linear-gradient(180deg, #585a5a 0%, #949198 100%);
+                  color: #ffffff;
+                }
+              }
+            }
+          }
+        }
+        .con {
+          flex: 3;
+          margin-top: -68px;
+          position: relative;
+          .back {
+            width: 19px;
+            position: absolute;
+            left: 26px;
+            top: 97px;
+            cursor: pointer;
+            > img {
+              width: 100%;
+            }
+          }
+          .detail {
+            width: 100%;
+            .detail-wrapper {
+              width: 95%;
+              margin: 152px auto 80px;
+              overflow: hidden;
+              .detail-picOrModel {
+                width: 100%;
+                img {
+                  width: 100%;
+                }
+                iframe {
+                  width: 100%;
+                  height: 700px;
+                }
+              }
+              .detail-title {
+                width: 100%;
+                text-align: center;
+                margin-top: 35px;
+                font-size: 24px;
+                font-family: Microsoft YaHei;
+                font-weight: 400;
+                line-height: 58px;
+                color: #202020;
+              }
+              .detail-desc {
+                text-align: center;
+                margin-top: 8px;
+                font-size: 12px;
+                font-weight: 400;
+              }
+              .detail-con {
+                margin-top: 31px;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 478 - 0
src/pages/collection/collection-type.vue

@@ -0,0 +1,478 @@
+<!--  -->
+<template>
+  <div class="collection-type">
+    <div class="wrapper">
+      <div class="top">
+        <img
+          class="bg"
+          :src="require('@/assets/images/survey-type-top-bg.png')"
+          alt=""
+        />
+      </div>
+      <div class="bottom">
+        <img
+          class="bg"
+          :src="require('@/assets/images/survey-type-bottom-bg.png')"
+          alt=""
+        />
+
+        <div class="content">
+          <div class="nav">
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-nav-bg.png')"
+              alt=""
+            />
+            <div class="nav-con">
+              <div class="nav-con-title">典藏</div>
+              <div class="nav-con-type">
+                <ul>
+                  <li
+                    :class="{ cur: collectionType === 'boutique' }"
+                    @click="switchType('boutique')"
+                  >
+                    <a>精品典藏</a>
+                    <div class="arrow" v-if="collectionType === 'boutique'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                  <li
+                    :class="{ cur: collectionType === 'threeDimensional' }"
+                    @click="switchType('threeDimensional')"
+                  >
+                    <a>三维藏品</a>
+                    <div
+                      class="arrow"
+                      v-if="collectionType === 'threeDimensional'"
+                    >
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                </ul>
+              </div>
+            </div>
+          </div>
+          <div class="con">
+            <!-- <div class="back" @click="back">
+              <img :src="require('@/assets/images/back.png')" alt="" />
+            </div> -->
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-con-bg.png')"
+              alt=""
+            />
+            <div class="search">
+              <div class="select">
+                <select v-model="params.goodsAgeId">
+                  <!-- <option value="" disabled selected style="display: none">
+                    年代
+                  </option> -->
+                  <option value="">全部</option>
+                  <option :value="item.id" v-for="(item,index) in getGoodAgeList" :key="index">{{item.name}}</option>
+                </select>
+              </div>
+              <div class="select">
+                <select v-model="params.goodsTypeId">
+                  <!-- <option value="" disabled selected style="display: none">
+                    分类
+                  </option> -->
+                  <option value="">全部</option>
+                  <option :value="item.id" v-for="(item,index) in getGoodTypeList" :key="index">{{item.name}}</option>
+                </select>
+              </div>
+              <div class="ipt">
+                <input
+                  type="text"
+                  v-model="params.searchKey"
+                  placeholder="输入名称"
+                />
+              </div>
+              <div class="btn" @click="search()">
+                <button>搜索</button>
+              </div>
+            </div>
+            <ul class="list">
+              <li
+                v-for="(item, index) in dataList"
+                :key="index"
+                @click="toDetail(item)"
+              >
+                <div class="pic">
+                  <img :src="$cdnUrl + item.thumb" alt="" />
+                </div>
+                <div class="cover">
+                  <div class="txt">
+                    <div class="txt-name">{{ item.name }}</div>
+                  </div>
+                </div>
+              </li>
+            </ul>
+            <el-empty :image-size="200" v-if="dataList.length === 0"></el-empty>
+            <div class="my-paging" v-if="dataList.length">
+              <Paging
+                v-if="paging.total"
+                :paging="paging"
+                @changeCurrent="pageChange"
+              />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+//例如:import 《组件名称》 from '《组件路径》';
+import Paging from "@/components/pagination";
+export default {
+  name: "collection-type",
+  //import引入的组件需要注入到对象中才能使用
+  components: {
+    Paging,
+  },
+  data() {
+    //这里存放数据
+    return {
+      collectionType: "boutique",
+      dataList: [],
+      paging: {
+        pageSize: 12,
+        pageNum: 1,
+        total: 0,
+        showSize: 12,
+        current: 1,
+      },
+      params: {
+        pageNum: 1,
+        pageSize: 12,
+        type: "",
+        goodsAgeId: "",
+        goodsTypeId: "",
+        searchKey:""
+      },
+      typeChange: {
+        boutique: "img",
+        threeDimensional: "model",
+      },
+      getGoodAgeList:[],
+      getGoodTypeList:[]
+    };
+  },
+  //监听属性 类似于data概念
+  computed: {},
+  //监控data中的数据变化
+  watch: {
+    paging: {
+      deep: true,
+      handler: function () {},
+    },
+  },
+  //方法集合
+  methods: {
+    async getList(reload=false) {
+      if(reload){
+        this.dataList = [];
+        this.params.pageNum = 1;
+      }
+      let result = await this.$http({
+        method: "post",
+        url: "/api/web/goods/list",
+        data: this.params,
+      });
+      this.dataList = result.data.list;
+      this.paging.total = result.data.total;
+    },
+    switchType(type) {
+      this.collectionType = type;
+      this.params["type"] = this.typeChange[this.collectionType];
+      this.params["pageNum"] = 1;
+      this.paging.current = 1;
+      this.getList();
+    },
+    back() {
+      this.$router.push({ path: "/collection" });
+    },
+    pageChange(val) {
+      console.log(val);
+      this.paging.current = val;
+      this.params.pageNum = val;
+      this.getList();
+    },
+    toDetail(item) {
+      this.$router.push({
+        path: "/collection-detail",
+        query: { ...item, navType: this.collectionType },
+      });
+    },
+    search() {
+      console.log(this.params);
+      this.getList(true);
+    },
+    async getGoodAge(){
+      let result = await this.$http({
+        method: "get",
+        url: "/api/web/goods/age/list",
+        data: this.params,
+      });
+      this.getGoodAgeList = result && result['code'] === 0 && result['data']
+      console.log('this.getGoodAgeList',this.getGoodAgeList)
+    },
+    async getGoodType(){
+      let result = await this.$http({
+        method: "get",
+        url: "/api/web/goods/type/list",
+        data: this.params,
+      });
+      this.getGoodTypeList = result && result['code'] === 0 && result['data']
+    }
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    this.collectionType =
+      (this.$route.query && this.$route.query["type"]) || "boutique";
+    this.params["type"] = this.typeChange[this.collectionType];
+    this.getList();
+    this.getGoodAge()
+    this.getGoodType()
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='less' scoped>
+.bg {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  left: 0;
+  top: 0;
+  z-index: -1;
+}
+.collection-type {
+  width: 100%;
+  margin-bottom: 98px;
+  .wrapper {
+    width: 100%;
+    .top {
+      width: 100%;
+      height: 278px;
+      position: relative;
+    }
+    .bottom {
+      width: 100%;
+      position: relative;
+      .content {
+        min-width: 1090px;
+        margin: 0 auto;
+        width: 57%;
+        display: flex;
+        justify-content: center;
+        .nav {
+          flex: 1;
+          margin-right: 1%;
+          margin-top: -68px;
+          position: relative;
+          .nav-con {
+            width: 85%;
+            margin: 94px auto 0;
+            .nav-con-title {
+              background: #a01c26ff;
+              padding: 14.5px 0 14.5px 46px;
+              font-size: 20px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #ffffff;
+              opacity: 1;
+            }
+            .nav-con-type {
+              margin-top: 3px;
+              background: rgba(160, 28, 38, 0.6);
+              overflow: hidden;
+              > ul {
+                width: 100%;
+                margin-top: 21px;
+                margin-bottom: 105px;
+                > li {
+                  width: 100%;
+                  padding: 8px 0 8px 51px;
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #000000;
+                  position: relative;
+                  cursor: pointer;
+                  .arrow {
+                    position: absolute;
+                    top: 10px;
+                    right: 11.5px;
+                    width: 10.5px;
+                    height: 18px;
+                    > img {
+                      width: 100%;
+                      height: 100%;
+                    }
+                  }
+                }
+                .cur {
+                  background: linear-gradient(180deg, #585a5a 0%, #949198 100%);
+                  color: #ffffff;
+                }
+              }
+            }
+          }
+        }
+        .con {
+          flex: 3;
+          margin-top: -68px;
+          position: relative;
+          overflow: hidden;
+          .back {
+            width: 19px;
+            position: absolute;
+            left: 26px;
+            top: 97px;
+            cursor: pointer;
+            > img {
+              width: 100%;
+            }
+          }
+          .search {
+            margin: 0 19px;
+            margin-top: 94px;
+            display: flex;
+            justify-content: flex-start;
+            height: 38px;
+            .select {
+              width: 22%;
+              height: 100%;
+              margin-right: 8px;
+              > select {
+                border-radius: 5px;
+                background: rgba(0, 0, 0, 0.4);
+                width: 100%;
+                height: 100%;
+                border:none;
+              }
+            }
+            .ipt {
+              width: 35%;
+              > input {
+                border-radius: 5px 0 0 5px;
+                width: 100%;
+                height: 100%;
+                padding-left: 16px;
+                color: #ffffff;
+                border: rgba(160, 28, 38, 0.4);
+                background: rgba(160, 28, 38, 0.4);
+                &::placeholder {
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  line-height: 21px;
+                  color: #ffffff;
+                  opacity: 0.7;
+                }
+              }
+            }
+            .btn {
+              width: 19%;
+              > button {
+                width: 100%;
+                height: 100%;
+                border: rgba(160, 28, 38, 1);
+                background: rgba(160, 28, 38, 1);
+                border-radius: 0 5px 5px 0;
+                font-size: 16px;
+                font-family: Microsoft YaHei;
+                font-weight: bold;
+                line-height: 21px;
+                letter-spacing: 2px;
+                color: #ffffff;
+                opacity: 1;
+              }
+            }
+          }
+          > ul {
+            margin: 30px 19px 62px;
+            display: flex;
+            align-items: center;
+            justify-content: flex-start;
+            flex-wrap: wrap;
+            > li {
+              display: flex;
+              align-items: center;
+              justify-content: center;
+              margin-bottom: 2%;
+              margin-right: 2%;
+              width: 32%;
+              height: 254px;
+              cursor: pointer;
+              position: relative;
+              //-----------------------------------
+              &:nth-of-type(3n) {
+                margin-right: 0;
+              }
+              .pic {
+                width: 100%;
+                height: 254px;
+                font-size: 0; // 消除img自带间距
+                position: relative;
+                overflow: hidden;
+                > img {
+                  width: 100%;
+                  position: absolute;
+                  top: 50%;
+                  left: 50%;
+                  transform: translate(-50%, -50%);
+                }
+              }
+              .cover {
+                width: 100%;
+                height: 100%;
+                background: rgba(160, 28, 38, 0.8);
+                box-shadow: 0 0 15px rgba(0, 0, 0, 1);
+                position: absolute;
+                top: 0;
+                left: 0;
+                display: none;
+                .txt {
+                  position: absolute;
+                  top: 50%;
+                  left: 50%;
+                  transform: translate(-50%, -50%);
+                  text-align: center;
+                  font-size: 24px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 300;
+                  color: #ffffff;
+                  opacity: 1;
+                  .txt-name {
+                  }
+                }
+              }
+              &:hover {
+                .cover {
+                  display: block;
+                }
+              }
+            }
+          }
+          .my-paging {
+            margin: 25px auto;
+            text-align: right;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 157 - 0
src/pages/collection/collection.vue

@@ -0,0 +1,157 @@
+<!--  -->
+<template>
+  <div class="collection">
+    <img class="bg" :src="require('@/assets/images/survey-bg.png')" alt="" />
+    <div class="content">
+      <div class="logo">
+        <img :src="require('@/assets/images/collection-title.png')" alt="" />
+      </div>
+      <ul>
+        <li
+          @click="toType('boutique')"
+          @mouseover="mouseOver('boutique')"
+          @mouseleave="mouseLeave('boutique')"
+        >
+          <img
+            :src="require(`@/assets/images/survey-mechanism${boutiqueHover?'-hover':''}.jpg`)"
+            alt=""
+          />
+          <div class="txt">精品典藏</div>
+        </li>
+        <li
+          @click="toType('threeDimensional')"
+          @mouseover="mouseOver('threeDimensional')"
+          @mouseleave="mouseLeave('threeDimensional')"
+        >
+          <img
+            :src="
+              require(`@/assets/images/exhibition-preview${
+                threeDimensionalHover ? '-hover' : ''
+              }.jpg`)
+            "
+            alt=""
+          />
+          <div class="txt">三维藏品</div>
+        </li>
+
+      </ul>
+    </div>
+  </div>
+</template>
+
+<script>
+//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+//例如:import 《组件名称》 from '《组件路径》';
+
+export default {
+  name: "collection",
+  //import引入的组件需要注入到对象中才能使用
+  components: {},
+  data() {
+    //这里存放数据
+    return {
+      boutiqueHover: false,
+      threeDimensionalHover: false,
+    };
+  },
+  //监听属性 类似于data概念
+  computed: {},
+  //监控data中的数据变化
+  watch: {},
+  //方法集合
+  methods: {
+    toType(type) {
+      this.$router.push({ path: "/collection-type", query: { type } });
+    },
+    mouseOver(type) {
+      switch (type) {
+        case "boutique":
+          this.boutiqueHover = true;
+          break;
+        case "threeDimensional":
+          this.threeDimensionalHover = true;
+          break;
+        default:
+          break;
+      }
+    },
+    mouseLeave(type) {
+      switch (type) {
+        case "boutique":
+          this.boutiqueHover = false;
+          break;
+        case "threeDimensional":
+          this.threeDimensionalHover = false;
+          break;
+        default:
+          break;
+      }
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='less' scoped>
+.collection {
+  width: 100%;
+  position: relative;
+  overflow: hidden;
+  .bg {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: -1;
+  }
+  .content {
+    margin: 66px auto 142px 464px;
+    display: flex;
+    .logo {
+      width: 120px;
+      > img {
+        width: 100%;
+      }
+    }
+    ul {
+      display: flex;
+      margin-left: 105px;
+      margin-top: 107px;
+      display: flex;
+      li {
+        width: 259px;
+        height: 624px;
+        position: relative;
+        margin-right: 23px;
+        cursor: pointer;
+        .txt {
+          width: 28px;
+          font-size: 28px;
+          font-family: Microsoft YaHei;
+          font-weight: 400;
+          line-height: 33px;
+          color: #000000;
+          opacity: 0.7;
+          position: absolute;
+          top: 9px;
+          right: 20px;
+        }
+        > img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+    }
+  }
+}
+</style>

+ 289 - 0
src/pages/exhibition/exhibition-detail.vue

@@ -0,0 +1,289 @@
+<!--  -->
+<template>
+  <div class="exhibition-detail">
+    <div class="wrapper">
+      <div class="top">
+        <img
+          class="bg"
+          :src="require('@/assets/images/exhibition-type-top-bg.png')"
+          alt=""
+        />
+        <div class="btn" @click="jumpTo()">线上展览<img :src="require('@/assets/images/exhibition-right-arrow.png')" alt=""/></div>
+      </div>
+      <div class="bottom">
+        <img
+          class="bg"
+          :src="require('@/assets/images/survey-type-bottom-bg.png')"
+          alt=""
+        />
+
+        <div class="content">
+          <div class="nav">
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-nav-bg.png')"
+              alt=""
+            />
+            <div class="nav-con">
+              <div class="nav-con-title">展览</div>
+              <div class="nav-con-type">
+                <ul>
+                  <li
+                    :class="{ cur: exhibitionType === 'hot' }"
+                    @click="switchType('hot')"
+                  >
+                    <a>正在热展</a>
+                    <div class="arrow" v-if="exhibitionType === 'hot'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                  <li
+                    :class="{ cur: exhibitionType === 'preview' }"
+                    @click="switchType('preview')"
+                  >
+                    <a>展览预告</a>
+                    <div class="arrow" v-if="exhibitionType === 'preview'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                  <li
+                    :class="{ cur: exhibitionType === 'review' }"
+                    @click="switchType('review')"
+                  >
+                    <a>展览回顾</a>
+                    <div class="arrow" v-if="exhibitionType === 'review'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                </ul>
+              </div>
+            </div>
+          </div>
+          <div class="con">
+            <div class="back" @click="back">
+              <img :src="require('@/assets/images/back.png')" alt="" />
+            </div>
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-con-bg.png')"
+              alt=""
+            />
+            <div class="detail">
+              <div class="detail-wrapper">
+                <div class="detail-title">{{ detail.name }}</div>
+                <div class="detail-desc">
+                  展览日期: {{ detail.startTime | dateFormat1('yyyy-MM-yy') }}-{{ detail.endTime | dateFormat1('yyyy-MM-yy') }}
+                </div>
+                <div class="detail-con" v-html="detail.content"></div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+//例如:import 《组件名称》 from '《组件路径》';
+export default {
+  name: "exhibition-detail",
+  //import引入的组件需要注入到对象中才能使用
+  components: {},
+  data() {
+    //这里存放数据
+    return {
+      exhibitionType: "hot",
+      detail: {},
+    };
+  },
+  //监听属性 类似于data概念
+  computed: {},
+  //监控data中的数据变化
+  watch: {},
+  //方法集合
+  methods: {
+    switchType(type) {
+      this.$router.push({ path: "/exhibition-type", query: { type } });
+    },
+    back() {
+      this.$router.push({
+        path: "/exhibition-type",
+        query: { type: this.detail.navType || "" },
+      });
+    },
+    jumpTo(){
+      window.open('http://www.4dmodel.com/SuperTwo/index.html?m=1025')
+    }
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    this.detail = this.$route.query;
+    this.exhibitionType = this.detail.navType;
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='less' scoped>
+.bg {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  left: 0;
+  top: 0;
+  z-index: -1;
+}
+.exhibition-detail {
+  width: 100%;
+  margin-bottom: 98px;
+  .wrapper {
+    width: 100%;
+    .top {
+      width: 100%;
+      height: 278px;
+      position: relative;
+      .btn {
+        position: absolute;
+        background: rgba(160, 28, 38, 1);
+        box-shadow: 0 0 6px rgba(255, 255, 255, 1);
+        text-align: center;
+        line-height: 55px;
+        width: 200px;
+        height: 55px;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%, -50%);
+        font-size: 20px;
+        font-family: Microsoft YaHei;
+        font-weight: 400;
+        color: #ffffff;
+        cursor: pointer;
+        >img {
+          position: absolute;
+          right: 20px;
+          top:14px;
+          width: 29px;
+          height: 29px;
+        }
+      }
+    }
+    .bottom {
+      width: 100%;
+      position: relative;
+      .content {
+        min-width: 1090px;
+        margin: 0 auto;
+        width: 57%;
+        display: flex;
+        justify-content: center;
+        .nav {
+          flex: 1;
+          margin-right: 1%;
+          margin-top: -68px;
+          position: relative;
+          .nav-con {
+            width: 85%;
+            margin: 94px auto 0;
+            .nav-con-title {
+              background: #a01c26ff;
+              padding: 14.5px 0 14.5px 46px;
+              font-size: 20px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #ffffff;
+              opacity: 1;
+            }
+            .nav-con-type {
+              margin-top: 3px;
+              background: rgba(160, 28, 38, 0.6);
+              overflow: hidden;
+              > ul {
+                width: 100%;
+                margin-top: 21px;
+                margin-bottom: 105px;
+                > li {
+                  width: 100%;
+                  padding: 8px 0 8px 51px;
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #000000;
+                  position: relative;
+                  cursor: pointer;
+                  .arrow {
+                    position: absolute;
+                    top: 10px;
+                    right: 11.5px;
+                    width: 10.5px;
+                    height: 18px;
+                    > img {
+                      width: 100%;
+                      height: 100%;
+                    }
+                  }
+                }
+                .cur {
+                  background: linear-gradient(180deg, #585a5a 0%, #949198 100%);
+                  color: #ffffff;
+                }
+              }
+            }
+          }
+        }
+        .con {
+          flex: 3;
+          margin-top: -68px;
+          position: relative;
+          .back {
+            width: 19px;
+            position: absolute;
+            left: 26px;
+            top: 97px;
+            cursor: pointer;
+            > img {
+              width: 100%;
+            }
+          }
+          .detail {
+            width: 100%;
+            .detail-wrapper {
+              width: 86%;
+              margin: 152px auto 80px;
+              max-width: 708px;
+              overflow-x: scroll;
+              .detail-title {
+                font-size: 40px;
+                font-family: Microsoft YaHei;
+                font-weight: 400;
+                line-height: 58px;
+                color: #000000;
+              }
+              .detail-desc {
+                margin-top: 36px;
+                margin-top: 8px;
+                font-size: 12px;
+                font-weight: 400;
+                font-size: 16px;
+                font-family: Microsoft YaHei;
+                color: #000000;
+              }
+              .detail-con {
+                margin-top: 62px;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 406 - 0
src/pages/exhibition/exhibition-type.vue

@@ -0,0 +1,406 @@
+<!--  -->
+<template>
+  <div class="exhibition-type">
+    <div class="wrapper">
+      <div class="top">
+        <img
+          class="bg"
+          :src="require('@/assets/images/exhibition-type-top-bg.png')"
+          alt=""
+        />
+        <div class="btn" @click="jumpTo(onlineLink)">线上展览<img :src="require('@/assets/images/exhibition-right-arrow.png')" alt=""/></div>
+      </div>
+      <div class="bottom">
+        <img
+          class="bg"
+          :src="require('@/assets/images/survey-type-bottom-bg.png')"
+          alt=""
+        />
+
+        <div class="content">
+          <div class="nav">
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-nav-bg.png')"
+              alt=""
+            />
+            <div class="nav-con">
+              <div class="nav-con-title">展览</div>
+              <div class="nav-con-type">
+                <ul>
+                  <li
+                    :class="{ cur: exhibitionType === 'hot' }"
+                    @click="switchType('hot')"
+                  >
+                    <a>正在热展</a>
+                    <div class="arrow" v-if="exhibitionType === 'hot'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                  <li
+                    :class="{ cur: exhibitionType === 'preview' }"
+                    @click="switchType('preview')"
+                  >
+                    <a>展览预告</a>
+                    <div class="arrow" v-if="exhibitionType === 'preview'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                  <li
+                    :class="{ cur: exhibitionType === 'review' }"
+                    @click="switchType('review')"
+                  >
+                    <a>展览回顾</a>
+                    <div class="arrow" v-if="exhibitionType === 'review'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                </ul>
+              </div>
+            </div>
+          </div>
+          <div class="con">
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-con-bg.png')"
+              alt=""
+            />
+            <ul class="list">
+              <li v-for="(item, index) in dataList" :key="index" @click="toDetail(item)">
+                <div class="pic">
+                  <img :src="$cdnUrl + item.thumb" alt="" />
+                </div>
+                <div class="cover">
+                  <div class="txt">
+                    <div class="txt-name">{{ item.name }}</div>
+                    <div class="txt-time">{{ item.startTime | dateFormat2('yyyy-MM-yy') }}-{{item.endTime | dateFormat2('yyyy-MM-yy') }}</div>
+                  </div>
+                </div>
+              </li>
+            </ul>
+            <el-empty :image-size="200" v-if="dataList.length === 0"></el-empty>
+            <div class="my-paging" v-if="dataList.length">
+              <Paging
+                v-if="paging.total"
+                :paging="paging"
+                @changeCurrent="pageChange"
+              />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+//例如:import 《组件名称》 from '《组件路径》';
+import Paging from "@/components/pagination";
+import { format } from 'date-fns'
+export default {
+  name: "exhibition-type",
+  //import引入的组件需要注入到对象中才能使用
+  components: {
+    Paging,
+  },
+  data() {
+    //这里存放数据
+    return {
+      exhibitionType: "hot",
+      dataList: [],
+      paging: {
+        pageSize: 9,
+        pageNum: 1,
+        total: 0,
+        showSize: 9,
+        current: 1,
+      },
+      params: {
+        pageNum: 1,
+        pageSize: 9,
+        type:''
+      },
+      typeChange: {
+        hot: "start",
+        preview: "unstart",
+        review: "end",
+      },
+    };
+  },
+  //监听属性 类似于data概念
+  computed: {},
+  //监控data中的数据变化
+  watch: {
+    paging: {
+      deep: true,
+      handler: function () {},
+    },
+  },
+  //方法集合
+  methods: {
+    async getList() {
+      let result = await this.$http({
+        method: "post",
+        url: "/api/web/exhibition/list",
+        data: this.params,
+      });
+      this.dataList = result.data.list;
+      this.paging.total = result.data.total;
+      console.log('this.dataList-----------------------',this.dataList)
+      //   // 暂时没有图片
+      this.dataList = this.dataList.map((item) => {
+        return {
+          ...item,
+          imgUrl:
+            "test-exhibition.png",
+        };
+      });
+    },
+    switchType(type) {
+      this.exhibitionType = type;
+      this.params["type"] = this.typeChange[this.exhibitionType];
+      this.params["pageNum"] = 1;
+      this.paging.current = 1;
+      this.getList();
+    },
+    back() {
+      this.$router.push({ path: "/exhibition" });
+    },
+    pageChange(val) {
+      console.log(val);
+      this.paging.current = val;
+      this.params.pageNum = val;
+      this.getList();
+    },
+    toDetail(item) {
+      this.$router.push({
+        path: "/exhibition-detail",
+        query: { ...item, navType: this.exhibitionType },
+      });
+    },
+    jumpTo(onlineLink){
+      window.open(onlineLink)
+    },
+    async getOnlineLink(){
+      let result = await this.$http({
+        method: "get",
+        url: "/api/web/exhibition/online",
+        data: this.params,
+      });
+      this.onlineLink = result && result.data && result.data.url;
+    }
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    this.exhibitionType =
+      (this.$route.query && this.$route.query["type"]) || "preview";
+    this.params["type"] = this.typeChange[this.exhibitionType];
+    this.getList();
+    this.getOnlineLink()
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='less' scoped>
+.bg {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  left: 0;
+  top: 0;
+  z-index: -1;
+}
+.exhibition-type {
+  width: 100%;
+  margin-bottom: 98px;
+  .wrapper {
+    width: 100%;
+    .top {
+      width: 100%;
+      height: 278px;
+      position: relative;
+      .btn {
+        position: absolute;
+        background: rgba(160, 28, 38, 1);
+        box-shadow: 0 0 6px rgba(255, 255, 255, 1);
+        text-align: center;
+        line-height: 55px;
+        width: 200px;
+        height: 55px;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%, -50%);
+        font-size: 20px;
+        font-family: Microsoft YaHei;
+        font-weight: 400;
+        color: #ffffff;
+        cursor: pointer;
+        >img {
+          position: absolute;
+          right: 20px;
+          top:14px;
+          width: 29px;
+          height: 29px;
+        }
+      }
+    }
+    .bottom {
+      width: 100%;
+      position: relative;
+      .content {
+        min-width: 1090px;
+        margin: 0 auto;
+        width: 57%;
+        display: flex;
+        justify-content: center;
+        .nav {
+          flex: 1;
+          margin-right: 1%;
+          margin-top: -68px;
+          position: relative;
+          .nav-con {
+            width: 85%;
+            margin: 94px auto 0;
+            .nav-con-title {
+              background: #a01c26ff;
+              padding: 14.5px 0 14.5px 46px;
+              font-size: 20px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #ffffff;
+              opacity: 1;
+            }
+            .nav-con-type {
+              margin-top: 3px;
+              background: rgba(160, 28, 38, 0.6);
+              overflow: hidden;
+              > ul {
+                width: 100%;
+                margin-top: 21px;
+                margin-bottom: 105px;
+                > li {
+                  width: 100%;
+                  padding: 8px 0 8px 51px;
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #000000;
+                  position: relative;
+                  cursor: pointer;
+                  .arrow {
+                    position: absolute;
+                    top: 10px;
+                    right: 11.5px;
+                    width: 10.5px;
+                    height: 18px;
+                    > img {
+                      width: 100%;
+                      height: 100%;
+                    }
+                  }
+                }
+                .cur {
+                  background: linear-gradient(180deg, #585a5a 0%, #949198 100%);
+                  color: #ffffff;
+                }
+              }
+            }
+          }
+        }
+        .con {
+          flex: 3;
+          margin-top: -68px;
+          position: relative;
+          .back {
+            width: 19px;
+            position: absolute;
+            left: 26px;
+            top: 97px;
+            cursor: pointer;
+            > img {
+              width: 100%;
+            }
+          }
+          > ul {
+            margin: 94px 19px 62px;
+            display: flex;
+            align-items: center;
+            justify-content: flex-start;
+            flex-wrap: wrap;
+            > li {
+              display: flex;
+              align-items: center;
+              justify-content: flex-start;
+              margin-bottom: 2%;
+              margin-right: 2%;
+              width: 32%;
+              cursor: pointer;
+              position: relative;
+              &:nth-of-type(3n){
+                  margin-right:0;
+              }
+              .pic {
+                width: 100%;
+                font-size: 0; // 消除img自带间距
+                > img {
+                  width: 100%;
+                }
+              }
+              .cover {
+                width: 100%;
+                height: 100%;
+                background: rgba(160, 28, 38, 0.8);
+                box-shadow: 0 0 15px rgba(0, 0, 0, 1);
+                position: absolute;
+                top: 0;
+                left: 0;
+                display: none;
+                .txt {
+                  width: 100%;
+                  position: absolute;
+                  top: 50%;
+                  left: 50%;
+                  transform: translate(-50%, -50%);
+                  text-align: center;
+                  font-size: 24px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 300;
+                  color: #ffffff;
+                  opacity: 1;
+                  .txt-name {
+                    width: 80%;
+                    margin: 0 auto;
+                    margin-bottom: 13px;
+                  }
+                  .txt-time {
+                    width: 80%;
+                    margin: 0 auto;
+                  }
+                }
+              }
+              &:hover {
+                  .cover {
+                      display: block;
+                  }
+              }
+            }
+          }
+          .my-paging {
+            margin: 25px auto;
+            text-align: right;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 184 - 0
src/pages/exhibition/exhibition.vue

@@ -0,0 +1,184 @@
+<!--  -->
+<template>
+  <div class="exhibition">
+    <img class="bg" :src="require('@/assets/images/survey-bg.png')" alt="" />
+    <div class="content">
+      <div class="logo">
+        <img :src="require('@/assets/images/exhibition-title.png')" alt="" />
+      </div>
+      <ul>
+        <li
+          @click="toType('hot')"
+          @mouseover="mouseOver('hot')"
+          @mouseleave="mouseLeave('hot')"
+        >
+          <img
+            :src="
+              require(`@/assets/images/exhibition-hot${
+                hotHover ? '-hover' : ''
+              }.jpg`)
+            "
+            alt=""
+          />
+          <div class="txt">正在热展</div>
+        </li>
+        <li
+          @click="toType('preview')"
+          @mouseover="mouseOver('preview')"
+          @mouseleave="mouseLeave('preview')"
+        >
+          <img
+            :src="
+              require(`@/assets/images/exhibition-preview${
+                previewHover ? '-hover' : ''
+              }.jpg`)
+            "
+            alt=""
+          />
+          <div class="txt">展览预告</div>
+        </li>
+
+        <li
+          @click="toType('review')"
+          @mouseover="mouseOver('review')"
+          @mouseleave="mouseLeave('review')"
+        >
+          <img
+            :src="
+              require(`@/assets/images/exhibition-review${
+                reviewHover ? '-hover' : ''
+              }.jpg`)
+            "
+            alt=""
+          />
+          <div class="txt">展览回顾</div>
+        </li>
+
+      </ul>
+    </div>
+  </div>
+</template>
+
+<script>
+//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+//例如:import 《组件名称》 from '《组件路径》';
+
+export default {
+  name: "exhibition",
+  //import引入的组件需要注入到对象中才能使用
+  components: {},
+  data() {
+    //这里存放数据
+    return {
+      hotHover: false,
+      previewHover: false,
+      reviewHover: false,
+    };
+  },
+  //监听属性 类似于data概念
+  computed: {},
+  //监控data中的数据变化
+  watch: {},
+  //方法集合
+  methods: {
+    toType(type) {
+      this.$router.push({ path: "/exhibition-type", query: { type } });
+    },
+    mouseOver(type) {
+      switch (type) {
+        case "hot":
+          this.hotHover = true;
+          break;
+        case "preview":
+          this.previewHover = true;
+          break;
+        case "review":
+          this.reviewHover = true;
+          break;
+        default:
+          break;
+      }
+    },
+    mouseLeave(type) {
+      switch (type) {
+        case "hot":
+          this.hotHover = false;
+          break;
+        case "preview":
+          this.previewHover = false;
+          break;
+        case "review":
+          this.reviewHover = false;
+          break;
+        default:
+          break;
+      }
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='less' scoped>
+.exhibition {
+  width: 100%;
+  position: relative;
+  overflow: hidden;
+  .bg {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: -1;
+  }
+  .content {
+    margin: 66px auto 142px 464px;
+    display: flex;
+    .logo {
+      width: 120px;
+      > img {
+        width: 100%;
+      }
+    }
+    ul {
+      display: flex;
+      margin-left: 105px;
+      margin-top: 107px;
+      display: flex;
+      li {
+        width: 259px;
+        height: 624px;
+        position: relative;
+        margin-right: 23px;
+        cursor: pointer;
+        .txt {
+          width: 28px;
+          font-size: 28px;
+          font-family: Microsoft YaHei;
+          font-weight: 400;
+          line-height: 33px;
+          color: #000000;
+          opacity: 0.7;
+          position: absolute;
+          top: 9px;
+          right: 20px;
+        }
+        > img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+    }
+  }
+}
+</style>

+ 86 - 0
src/pages/home/home.vue

@@ -0,0 +1,86 @@
+<template>
+  <div class="home">
+    <swiper :options="swiperOption" ref="mySwiper">
+      <swiper-slide v-for="(item, index) in sliceArr" :key="index"
+        ><img :src="$cdnUrl+item.ossPath" alt=""
+      /></swiper-slide>
+      <div class="swiper-pagination" slot="pagination"></div>
+      <div class="swiper-button-prev" slot="button-prev"></div>
+      <div class="swiper-button-next" slot="button-next"></div>
+    </swiper>
+  </div>
+</template>
+
+<script>
+import { Swiper, SwiperSlide } from "vue-awesome-swiper";
+import "swiper/css/swiper.css";
+export default {
+  components: {
+    Swiper,
+    SwiperSlide,
+  },
+  name: "index",
+  data() {
+    return {
+      sliceArr: [],
+      swiperOption: {
+        pagination: {
+          el: ".swiper-pagination",
+          clickable: true,
+        },
+        navigation: {
+          nextEl: ".swiper-button-next",
+          prevEl: ".swiper-button-prev",
+        },
+        loop: true,
+        autoplay: {
+          disableOnInteraction: false,
+          delay: 4000,
+        },
+      },
+    };
+  },
+  created() {
+    this.getSlideList()
+  },
+  methods: {
+    async getSlideList() {
+      let result = await this.$http({
+        method:'post',
+        url:'/api/web/slideshow/list'
+      })
+      this.sliceArr = result && result['code'] === 0 && result['data'] || []
+    }
+  },
+  computed: {
+    swiper() {
+      return this.$refs.mySwiper.$swiper;
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.home {
+  width: 100%;
+  .swiper-slide {
+    width: 100%;
+    // display:flex;
+    // font-size:0;
+    > img {
+      display: block; // 行内元素img 自带间距
+      width: 100%;
+    }
+  }
+}
+</style>
+
+<style lang="less">
+.swiper-button-prev::after,
+  .swiper-button-next::after {
+    color: #808080;
+  }
+.swiper-pagination-bullet-active {
+  background: #808080!important;
+}
+</style>

+ 339 - 0
src/pages/information/information-detail.vue

@@ -0,0 +1,339 @@
+<!--  -->
+<template>
+  <div class="survey-type">
+    <div class="wrapper">
+      <div class="top">
+        <img
+          class="bg"
+          :src="require('@/assets/images/information-type-top-bg.png')"
+          alt=""
+        />
+      </div>
+      <div class="bottom">
+        <img
+          class="bg"
+          :src="require('@/assets/images/survey-type-bottom-bg.png')"
+          alt=""
+        />
+
+        <div class="content">
+          <div class="nav">
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-nav-bg.png')"
+              alt=""
+            />
+            <div class="nav-con">
+              <div class="nav-con-title">资讯</div>
+              <div class="nav-con-type">
+                <ul>
+                  <li
+                    :class="{ cur: informationType === 'recentNews' }"
+                    @click="switchType('recentNews')"
+                  >
+                    <a>近期新闻</a>
+                    <div class="arrow" v-if="informationType === 'recentNews'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                  <li
+                    :class="{ cur: informationType === 'activity' }"
+                    @click="switchType('activity')"
+                  >
+                    <a>专项活动</a>
+                    <div class="arrow" v-if="informationType === 'activity'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                  <li
+                    :class="{ cur: informationType === 'infor' }"
+                    @click="switchType('infor')"
+                  >
+                    <a>信息公开</a>
+                    <div class="arrow" v-if="informationType === 'infor'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                  <li
+                    :class="{ cur: informationType === 'book' }"
+                    @click="switchType('book')"
+                  >
+                    <a>出版书籍</a>
+                    <div class="arrow" v-if="informationType === 'book'">
+                      <img :src="require('@/assets/images/arrow.png')" alt="" />
+                    </div>
+                  </li>
+                </ul>
+              </div>
+            </div>
+          </div>
+          <div class="con">
+            <div class="back" @click="back">
+              <img :src="require('@/assets/images/back.png')" alt="" />
+            </div>
+            <img
+              class="bg"
+              :src="require('@/assets/images/survey-type-con-bg.png')"
+              alt=""
+            />
+            <div class="detail">
+              <div class="detail-wrapper">
+                <div class="detail-title">{{ detail.name }}</div>
+                <div class="detail-desc">
+                  <span
+                    >发布时间:&nbsp;{{ detail.createTime | dateFormat('yyyy-MM-yy') }}&nbsp;&nbsp;</span
+                  >
+                  <span>分类:&nbsp;{{ detail.type === 'news'? '近期新闻': detail.type === 'activity'? '专项活动': detail.type === 'info'? '信息公开':''}}</span>
+                </div>
+                <div class="detail-con" v-html="detail.content"></div>
+              </div>
+              <!-- <div class="bottom-nav">
+                <div class="bottom-nav-left">
+                  <img
+                    :src="require('@/assets/images/paging-prev.png')"
+                    alt=""
+                  />
+                  <a class="prev-title">上一篇&nbsp;&nbsp;标题标题</a>
+                </div>
+                <div class="bottom-nav-right">
+                  <a class="next-title">下一篇&nbsp;&nbsp;标题标题</a>
+                  <img
+                    :src="require('@/assets/images/paging-next.png')"
+                    alt=""
+                  />
+                </div>
+              </div> -->
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+//例如:import 《组件名称》 from '《组件路径》';
+import Paging from "@/components/pagination";
+export default {
+  name: "survey",
+  //import引入的组件需要注入到对象中才能使用
+  components: {
+    Paging,
+  },
+  data() {
+    //这里存放数据
+    return {
+      informationType: "recentNews",
+      detail: {},
+    };
+  },
+  //监听属性 类似于data概念
+  computed: {},
+  //监控data中的数据变化
+  watch: {},
+  //方法集合
+  methods: {
+    switchType(type) {
+      this.$router.push({ path: "/information-type", query: { type } });
+    },
+    back() {
+      this.$router.push({
+        path: "/information-type",
+        query: { type: this.detail.navType || "" },
+      });
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    // console.log("this.$route.query", this.$route.query);
+    this.detail = this.$route.query;
+    this.informationType = this.detail.navType;
+    // console.log("this.detail", this.detail);
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='less' scoped>
+.bg {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  left: 0;
+  top: 0;
+  z-index: -1;
+}
+.survey-type {
+  width: 100%;
+  margin-bottom: 98px;
+  .wrapper {
+    width: 100%;
+    .top {
+      width: 100%;
+      height: 278px;
+      position: relative;
+    }
+    .bottom {
+      width: 100%;
+      position: relative;
+      .content {
+        min-width: 1090px;
+        margin: 0 auto;
+        width: 57%;
+        display: flex;
+        justify-content: center;
+        .nav {
+          flex: 1;
+          margin-right: 1%;
+          margin-top: -68px;
+          position: relative;
+          .nav-con {
+            width: 85%;
+            margin: 94px auto 0;
+            .nav-con-title {
+              background: #a01c26ff;
+              padding: 14.5px 0 14.5px 46px;
+              font-size: 20px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #ffffff;
+              opacity: 1;
+            }
+            .nav-con-type {
+              margin-top: 3px;
+              background: rgba(160, 28, 38, 0.6);
+              overflow: hidden;
+              > ul {
+                width: 100%;
+                margin-top: 21px;
+                margin-bottom: 105px;
+                > li {
+                  width: 100%;
+                  padding: 8px 0 8px 51px;
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #000000;
+                  position: relative;
+                  cursor: pointer;
+                  .arrow {
+                    position: absolute;
+                    top: 10px;
+                    right: 11.5px;
+                    width: 10.5px;
+                    height: 18px;
+                    > img {
+                      width: 100%;
+                      height: 100%;
+                    }
+                  }
+                }
+                .cur {
+                  background: linear-gradient(180deg, #585a5a 0%, #949198 100%);
+                  color: #ffffff;
+                }
+              }
+            }
+          }
+        }
+        .con {
+          flex: 3;
+          margin-top: -68px;
+          position: relative;
+          .back {
+            width: 19px;
+            position: absolute;
+            left: 26px;
+            top: 97px;
+            cursor: pointer;
+            > img {
+              width: 100%;
+            }
+          }
+          .detail {
+            width: 100%;
+            .detail-wrapper {
+              font-family: Microsoft YaHei;
+              color: #202020;
+              line-height: 24px;
+              width: 86%;
+              margin: 152px auto 80px;
+              max-width: 708px;
+              overflow-x: scroll;
+              .detail-title {
+                text-align: center;
+                font-size: 18px;
+                font-weight: bold;
+              }
+              .detail-desc {
+                text-align: center;
+                margin-top: 8px;
+                font-size: 12px;
+                font-weight: 400;
+              }
+              .detail-con {
+                margin-top: 32px;
+              }
+            }
+            .bottom-nav {
+              width: 100%;
+              display: flex;
+              justify-content: space-between;
+              height: 61px;
+              line-height: 61px;
+              .bottom-nav-left,
+              .bottom-nav-right {
+                cursor: pointer;  
+                overflow: hidden;
+                > img {
+                  width: 16px;
+                  vertical-align: middle;
+                }
+                > a {
+                  vertical-align: middle;
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: bold;
+                  line-height: 21px;
+                  color: #000000;
+                  opacity: 0.8;
+                }
+              }
+              .bottom-nav-left {
+                  margin-left: 64px;
+                  > img {
+                      margin-right: 10px;
+                  }
+                  &:hover {
+                      >a {
+                          color:rgba(160, 28, 38, 1);
+                      }
+                  }
+              }
+              .bottom-nav-right {
+                  margin-right: 64px;
+                  > img {
+                      margin-left: 10px;
+                  }
+                  &:hover {
+                      >a {
+                          color:rgba(160, 28, 38, 1);
+                      }
+                  }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 0 - 0
src/pages/information/information-type.vue


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است