Browse Source

first commit

James 4 years ago
commit
b35c4c6c7f
100 changed files with 27878 additions and 0 deletions
  1. 3 0
      .browserslistrc
  2. 23 0
      .eslintrc.js
  3. 21 0
      .gitignore
  4. 24 0
      README.md
  5. 5 0
      babel.config.js
  6. 11879 0
      package-lock.json
  7. 34 0
      package.json
  8. BIN
      public/favicon.png
  9. BIN
      public/favicon1.png
  10. 19 0
      public/index.html
  11. 31 0
      src/App.vue
  12. 0 0
      src/assets/css/color.less
  13. 4 0
      src/assets/css/globalVars.less
  14. 302 0
      src/assets/css/public.less
  15. 109 0
      src/assets/css/reset.less
  16. 539 0
      src/assets/font/demo.css
  17. 607 0
      src/assets/font/demo_index.html
  18. BIN
      src/assets/font/download.zip
  19. 93 0
      src/assets/font/iconfont.css
  20. BIN
      src/assets/font/iconfont.eot
  21. 1 0
      src/assets/font/iconfont.js
  22. 142 0
      src/assets/font/iconfont.json
  23. 83 0
      src/assets/font/iconfont.svg
  24. BIN
      src/assets/font/iconfont.ttf
  25. BIN
      src/assets/font/iconfont.woff
  26. BIN
      src/assets/font/iconfont.woff2
  27. BIN
      src/assets/img/01jk.png
  28. BIN
      src/assets/img/01jks.png
  29. BIN
      src/assets/img/02fb.png
  30. BIN
      src/assets/img/03mg.png
  31. BIN
      src/assets/img/04fb.png
  32. BIN
      src/assets/img/4dage-logo.png
  33. BIN
      src/assets/img/bg.jpg
  34. BIN
      src/assets/img/biyan.png
  35. BIN
      src/assets/img/del.png
  36. BIN
      src/assets/img/delete.png
  37. BIN
      src/assets/img/edit.png
  38. BIN
      src/assets/img/logo.png
  39. BIN
      src/assets/img/logout.png
  40. BIN
      src/assets/img/noPicture.png
  41. BIN
      src/assets/img/plus.png
  42. BIN
      src/assets/img/user.png
  43. BIN
      src/assets/img/wenli.png
  44. BIN
      src/assets/img/zhoushan-logo.jpg
  45. 71 0
      src/components/Editor.vue
  46. 266 0
      src/components/Tinymce/index.vue
  47. 5 0
      src/components/Tinymce/plugins.js
  48. 3 0
      src/components/Tinymce/toolbar.js
  49. 58 0
      src/components/crumbs/index.vue
  50. 86 0
      src/components/main-top/index.vue
  51. 175 0
      src/components/picture-upload/index.vue
  52. 60 0
      src/configue/base.js
  53. 3 0
      src/configue/bus.js
  54. 151 0
      src/configue/http.js
  55. 12 0
      src/filters/index.js
  56. 151 0
      src/main.js
  57. 149 0
      src/pages/activity/activityEdit.vue
  58. 270 0
      src/pages/activity/activityList.vue
  59. 324 0
      src/pages/collection/collectionEdit.vue
  60. 264 0
      src/pages/collection/collectionList.vue
  61. 116 0
      src/pages/collection/collectionSortEdit.vue
  62. 203 0
      src/pages/collection/collectionSortList.vue
  63. 116 0
      src/pages/collection/collectionYearEdit.vue
  64. 203 0
      src/pages/collection/collectionYearList.vue
  65. 679 0
      src/pages/content/Carousel.vue
  66. 569 0
      src/pages/content/Collection.vue
  67. 424 0
      src/pages/content/Comment.vue
  68. 742 0
      src/pages/content/Dynamic.vue
  69. 857 0
      src/pages/content/Spirit.vue
  70. 762 0
      src/pages/content/sceneAudio.vue
  71. 374 0
      src/pages/edit/carousel.vue
  72. 710 0
      src/pages/edit/collection.vue
  73. 447 0
      src/pages/edit/dynamic.vue
  74. 422 0
      src/pages/edit/spirit.vue
  75. 261 0
      src/pages/exhibition/exhibitionEdit.vue
  76. 229 0
      src/pages/exhibition/exhibitionList.vue
  77. 124 0
      src/pages/exhibition/exhibitionOnline.vue
  78. 267 0
      src/pages/home/rotation.vue
  79. 226 0
      src/pages/home/rotationEdit.vue
  80. 244 0
      src/pages/layout/aside.vue
  81. 47 0
      src/pages/layout/footer.vue
  82. 148 0
      src/pages/layout/head.vue
  83. 56 0
      src/pages/layout/index.vue
  84. 130 0
      src/pages/leaveMessage/guide.vue
  85. 244 0
      src/pages/leaveMessage/leaveMessageList.vue
  86. 227 0
      src/pages/login/index.vue
  87. 3 0
      src/pages/login/style.css
  88. 241 0
      src/pages/news/bookEdit.vue
  89. 226 0
      src/pages/news/bookList.vue
  90. 174 0
      src/pages/news/newEdit.vue
  91. 253 0
      src/pages/news/newsList.vue
  92. 310 0
      src/pages/questionnaire/questionnaireEdit.vue
  93. 250 0
      src/pages/questionnaire/questionnaireList.vue
  94. 148 0
      src/pages/questionnaire/questionnaireResult.vue
  95. 363 0
      src/pages/show/parts.vue
  96. 245 0
      src/pages/show/roam.vue
  97. 236 0
      src/pages/show/structure.vue
  98. 150 0
      src/pages/survey/surveyList.vue
  99. 485 0
      src/pages/system/Download.vue
  100. 0 0
      src/pages/system/Menu.vue

+ 3 - 0
.browserslistrc

@@ -0,0 +1,3 @@
+> 1%
+last 2 versions
+not dead

+ 23 - 0
.eslintrc.js

@@ -0,0 +1,23 @@
+module.exports = {
+  root: true,
+  env: {
+    node: true
+  },
+  'extends': [
+    'plugin:vue/essential',
+    'eslint:recommended'
+  ],
+  parserOptions: {
+    parser: 'babel-eslint'
+  },
+  rules: {
+    // 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+    // 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+    "generator-star-spacing": "off",
+        "no-tabs":"off",
+        "no-unused-vars":"off",
+        "no-console":"off",
+        "no-irregular-whitespace":"off",
+        "no-debugger": "off"
+  }
+}

+ 21 - 0
.gitignore

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

+ 24 - 0
README.md

@@ -0,0 +1,24 @@
+# sh_backstage
+
+## Project setup
+```
+npm install
+```
+
+### Compiles and hot-reloads for development
+```
+npm run serve
+```
+
+### Compiles and minifies for production
+```
+npm run build
+```
+
+### Lints and fixes files
+```
+npm run lint
+```
+
+### Customize configuration
+See [Configuration Reference](https://cli.vuejs.org/config/).

+ 5 - 0
babel.config.js

@@ -0,0 +1,5 @@
+module.exports = {
+  presets: [
+    '@vue/cli-plugin-babel/preset'
+  ]
+}

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


+ 34 - 0
package.json

@@ -0,0 +1,34 @@
+{
+  "name": "sh_backstage",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "axios": "^0.19.2",
+    "core-js": "^3.6.4",
+    "element-ui": "^2.13.2",
+    "js-base64": "^2.6.2",
+    "uuid": "^8.3.2",
+    "vue": "^2.6.11",
+    "vue-layer": "^1.2.5",
+    "vue-quill-editor": "^3.0.6",
+    "vue-router": "^3.1.6",
+    "vue2-editor": "^2.10.2"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.3.0",
+    "@vue/cli-plugin-eslint": "~4.3.0",
+    "@vue/cli-plugin-router": "~4.3.0",
+    "@vue/cli-service": "~4.3.0",
+    "babel-eslint": "^10.1.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-vue": "^6.2.2",
+    "less": "^3.0.4",
+    "less-loader": "^5.0.0",
+    "vue-template-compiler": "^2.6.11"
+  }
+}

BIN
public/favicon.png


BIN
public/favicon1.png


+ 19 - 0
public/index.html

@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+  <head>
+    <meta charset="utf-8">
+    <meta name="google" content="notranslate" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="renderer" content="webkit">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, minimal-ui">
+    <link rel="icon" href="<%= BASE_URL %>favicon.png">
+    <title>大理博物馆管理后台</title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 31 - 0
src/App.vue

@@ -0,0 +1,31 @@
+<template>
+  <div id="app">
+    <router-view/>
+  </div>
+</template>
+
+<script>
+import '@/assets/css/reset.less'
+import '@/assets/css/public.less'
+import '@/assets/font/iconfont.css'
+import Vue from 'vue'
+
+
+export default {
+  name: 'App',
+  created(){
+    if (window.localStorage.getItem('userInfo')) {
+      Vue.prototype.$role = JSON.parse(window.localStorage.getItem('userInfo')).role
+    }
+  }
+}
+
+</script>
+
+<style>
+  #app{
+    width: 100%;
+    height: 100%;
+    background-color: #f0f0f2;
+  }
+</style>

+ 0 - 0
src/assets/css/color.less


+ 4 - 0
src/assets/css/globalVars.less

@@ -0,0 +1,4 @@
+@cdn:'https://4d-tjw.oss-cn-shenzhen.aliyuncs.com/shls_museum/images/';
+@inputH:30px;
+@theme:#9D362F;
+@sub-theme:#C58C63;

+ 302 - 0
src/assets/css/public.less

@@ -0,0 +1,302 @@
+*{
+  font-family: 'Microsoft YaHei';
+}
+input::-webkit-inner-spin-button{
+  appearance: none;
+  margin: 0;
+}
+
+.layout{
+  width: 100%;
+  height: 100%;
+}
+
+.layout-con{
+  width: 100%;
+  height: 100%;
+  position: fixed;
+}
+
+
+.paddingmore .el-input__inner{
+  padding: 0 60px 0 15px!important;
+}
+
+.middle-title, .register-title,.forget-title{
+  color: #4d4d4d;
+  font-size: 1.75rem;
+  text-align: center;
+  margin-bottom: 3.4375rem;
+  line-height: 1.5;
+}
+
+.register-title,.forget-title{
+  margin-top: 1.25rem;
+}
+
+.middle{
+  position: absolute;
+  top: 30vh;
+  left: 50vw;
+  width: 23.75rem;
+  height: 18.75rem;
+  transform: translate(-50%,-50%);
+}
+.middle-subtitle{
+  font-size: .875rem;
+  font-weight: 500;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.middle-subtitle::before,.middle-subtitle::after{
+  content: '';
+  height: 0rem;
+  width: 1.25rem;
+  border: .03125rem solid #000; 
+  display: inline-block;
+  margin: 0 .625rem;
+}
+
+.form-bottom{
+  display: flex;
+  justify-content: space-between;
+  padding: 0 .625rem;
+  color: #888;
+}
+
+.form-bottom span{
+  cursor: pointer;
+}
+
+.bottom-div{
+  text-align: center;
+  cursor: pointer;
+  color: #888888;
+}
+
+.test-btn{
+  color: #67c23a!important;
+}
+
+.view-btn{
+  color: #409eff!important;
+}
+.re-apply-btn{
+  color: #f56c6c!important;
+}
+.apply-btn{
+  color: #ec652d!important;
+}
+
+.noCursor .el-upload{
+  cursor: no-drop!important;
+}
+.o-span{
+  cursor: pointer;
+  color: rgb(7, 152, 244);
+}
+
+.o-delete{
+    cursor: pointer;
+    color: #707070;
+    margin-left: 5px;
+    &:hover{
+      color: #409EFF;
+    }
+}
+
+
+.e-pagination{
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 1.5625rem;
+}
+
+:root{
+  --bg_color:rgba(255, 255, 255, 1);
+  --font_color:rgba(0, 0, 0, 0.88);
+  --font_color1:rgba(0, 0, 0, 0.38);
+}
+
+.theme{
+  background: #f2ecde!important;
+}
+
+.theme-color{
+  color: var(--font_color)!important;
+}
+
+.theme-color1{
+  color: var(--font_color1)!important;
+}
+
+.card,.top-body {
+  background: var(--bg_color)!important;
+  border-radius: 2px!important;
+  color: #000!important;
+  border: none!important;
+}
+.top-body {
+  margin: 0 auto 1rem!important;
+}
+
+.info-right{
+  padding-right: 15px;
+}
+
+.el-icon-upload{
+  margin: 20px auto!important;
+}
+
+.el-upload__text p{
+  line-height:1.2!important;
+  font-size:12px!important;
+  margin-bottom: 10px!important;
+  color: #ccc!important;
+}
+
+
+.li-img{
+  max-height: 237px;
+  overflow: hidden;
+  width: 100%;
+  position: relative;
+  img{
+  }
+  .eye{
+    z-index: 9999;
+    position: absolute;
+    right: 10px;
+    top: 10px;
+    width: 20px!important;
+  }
+}
+.collection-con .nodata{
+  width: 100%;
+  padding-top: 10%;
+  text-align: center;
+}
+
+.tab{
+  padding-top: 20px;
+  >li{
+    display: inline-block;
+    margin-right: 20px;
+    padding-bottom: 10px;
+    cursor: pointer;
+  }
+  .active{
+    color: #B63C25;
+    border-bottom: 2px solid #B63C25;
+  }
+}
+
+.main-title {
+  margin: 50px 0;
+  .eidtor{
+    margin: 20px;
+  }
+}
+.title {
+  color: #707070;
+  font-weight: bold;
+  font-size: 14px;
+  margin-bottom: 20px;
+}
+
+.reason{
+  background: #fff;
+  height: 40px;
+  width: 100%;
+  margin-bottom: 10px;
+  line-height: 40px;
+  padding-left: 20px;
+}
+
+
+.text-con{
+  border: 1px solid #ccc;
+  padding: 10px;
+  min-height: 100px;
+  width: calc(100% - 10px) ;
+  margin-left: 20px;
+  color: #ccc;
+}
+
+.icenter{
+  /deep/.el-input__inner{
+    text-align: center;
+  }
+}
+
+.image-slot{
+  min-height: 100px;
+  height: 100%;
+  min-width: 230px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background: #dddddd;
+  padding: 0 10px;
+  >i{
+    font-size: 40px;
+  }
+}
+
+@media screen and (max-width: 1700px) {
+  html,body{
+    font-size: 15px;
+  }
+}
+
+.con-btn{
+  margin-right: 20px;
+}
+
+.o-span{
+  padding-left: 10px;
+}
+.el-tabs__item{
+  font-size: 16px!important;
+  font-weight: bold!important;
+}
+
+.elInput{
+  width:200px!important;
+  margin:0 20px!important;
+}
+.elSelect{
+  width:150px!important;
+}
+
+@media screen and (max-width: 1400px) {
+  html,body{
+    font-size: 13px;
+  }
+  .collection-con{
+    height: 58vh!important;
+  }
+  .elInput{
+    width:150px!important;
+    margin:0 20px!important;
+  }
+  .elSelect{
+    width:100px!important;
+  }
+}
+
+
+@media screen and (max-width: 1300px) {
+  html,body{
+    font-size: 12px;
+  }
+  .collection-con{
+    height: 61vh!important;
+  }
+  .elInput{
+    width:130px!important;
+    margin:0 10px!important;
+  }
+}

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

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

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

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

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

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

BIN
src/assets/font/download.zip


File diff suppressed because it is too large
+ 93 - 0
src/assets/font/iconfont.css


BIN
src/assets/font/iconfont.eot


File diff suppressed because it is too large
+ 1 - 0
src/assets/font/iconfont.js


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

@@ -0,0 +1,142 @@
+{
+  "id": "1855608",
+  "name": "大理博物馆管理后台",
+  "font_family": "iconfont",
+  "css_prefix_text": "icon",
+  "description": "展示界面和管理后台",
+  "glyphs": [
+    {
+      "icon_id": "15079056",
+      "name": "previous",
+      "font_class": "previous",
+      "unicode": "e6f1",
+      "unicode_decimal": 59121
+    },
+    {
+      "icon_id": "15079057",
+      "name": "Page_ele",
+      "font_class": "Page_ele",
+      "unicode": "e6f2",
+      "unicode_decimal": 59122
+    },
+    {
+      "icon_id": "15079058",
+      "name": "next",
+      "font_class": "next",
+      "unicode": "e6f3",
+      "unicode_decimal": 59123
+    },
+    {
+      "icon_id": "15079059",
+      "name": "sys_nav_index",
+      "font_class": "sys_nav_index",
+      "unicode": "e6f4",
+      "unicode_decimal": 59124
+    },
+    {
+      "icon_id": "15079060",
+      "name": "search",
+      "font_class": "search",
+      "unicode": "e6f5",
+      "unicode_decimal": 59125
+    },
+    {
+      "icon_id": "15079061",
+      "name": "sys_edit",
+      "font_class": "sys_edit",
+      "unicode": "e6f6",
+      "unicode_decimal": 59126
+    },
+    {
+      "icon_id": "15079062",
+      "name": "Page",
+      "font_class": "Page",
+      "unicode": "e6f7",
+      "unicode_decimal": 59127
+    },
+    {
+      "icon_id": "15079063",
+      "name": "sys_down",
+      "font_class": "sys_down",
+      "unicode": "e6f8",
+      "unicode_decimal": 59128
+    },
+    {
+      "icon_id": "15079064",
+      "name": "sys_nav_work",
+      "font_class": "sys_nav_work",
+      "unicode": "e6f9",
+      "unicode_decimal": 59129
+    },
+    {
+      "icon_id": "15079065",
+      "name": "sys_nav_system",
+      "font_class": "sys_nav_system",
+      "unicode": "e6fa",
+      "unicode_decimal": 59130
+    },
+    {
+      "icon_id": "15079066",
+      "name": "tit_ele",
+      "font_class": "tit_ele",
+      "unicode": "e6fb",
+      "unicode_decimal": 59131
+    },
+    {
+      "icon_id": "15079018",
+      "name": "mode",
+      "font_class": "mode",
+      "unicode": "e6ef",
+      "unicode_decimal": 59119
+    },
+    {
+      "icon_id": "15079019",
+      "name": "nav_guestbook",
+      "font_class": "nav_guestbook",
+      "unicode": "e6f0",
+      "unicode_decimal": 59120
+    },
+    {
+      "icon_id": "15078995",
+      "name": "guestbook_btnbg_first",
+      "font_class": "guestbook_btnbg_first",
+      "unicode": "e6e9",
+      "unicode_decimal": 59113
+    },
+    {
+      "icon_id": "15078996",
+      "name": "btnbg_normal",
+      "font_class": "btnbg_normal",
+      "unicode": "e6ea",
+      "unicode_decimal": 59114
+    },
+    {
+      "icon_id": "15078997",
+      "name": "guestbook_success",
+      "font_class": "guestbook_success",
+      "unicode": "e6eb",
+      "unicode_decimal": 59115
+    },
+    {
+      "icon_id": "15078998",
+      "name": "guestbook_close",
+      "font_class": "guestbook_close",
+      "unicode": "e6ec",
+      "unicode_decimal": 59116
+    },
+    {
+      "icon_id": "15078999",
+      "name": "logo_tit",
+      "font_class": "logo_tit",
+      "unicode": "e6ed",
+      "unicode_decimal": 59117
+    },
+    {
+      "icon_id": "15079000",
+      "name": "logo_normal",
+      "font_class": "logo_normal",
+      "unicode": "e6ee",
+      "unicode_decimal": 59118
+    }
+  ]
+}

File diff suppressed because it is too large
+ 83 - 0
src/assets/font/iconfont.svg


BIN
src/assets/font/iconfont.ttf


BIN
src/assets/font/iconfont.woff


BIN
src/assets/font/iconfont.woff2


BIN
src/assets/img/01jk.png


BIN
src/assets/img/01jks.png


BIN
src/assets/img/02fb.png


BIN
src/assets/img/03mg.png


BIN
src/assets/img/04fb.png


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


BIN
src/assets/img/bg.jpg


BIN
src/assets/img/biyan.png


BIN
src/assets/img/del.png


BIN
src/assets/img/delete.png


BIN
src/assets/img/edit.png


BIN
src/assets/img/logo.png


BIN
src/assets/img/logout.png


BIN
src/assets/img/noPicture.png


BIN
src/assets/img/plus.png


BIN
src/assets/img/user.png


BIN
src/assets/img/wenli.png


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


+ 71 - 0
src/components/Editor.vue

@@ -0,0 +1,71 @@
+<template>
+  <div>
+    <VueEditor
+      ref="editor"
+      @text-change="textChange"
+      v-model="editContent"
+      @image-added="handleImageAdded"
+      useCustomImageHandler
+    ></VueEditor>
+  </div>
+</template>
+
+<script>
+import { VueEditor } from "vue2-editor";
+
+export default {
+  props: {
+    content: {
+      default: "",
+      type: String,
+    },
+  },
+  data() {
+    return {
+        editContent:''
+    };
+  },
+  watch:{
+      content(newVal){
+        this.editContent = newVal
+      }
+  },
+  mounted(){
+      this.$nextTick(()=>{
+        this.editContent = this.content
+      })
+  },
+  components: {
+    VueEditor,
+  },
+  methods: {
+    textChange() {
+      this.$emit("onchange", this.editContent);
+    },
+    async handleImageAdded(file, Editor, cursorLocation, resetUploader) {
+      var formData = new FormData();
+      formData.append("file", file);
+      let result = await this.$http({
+        method: "post",
+        data: formData,
+        headers: {
+          token: window.localStorage.getItem("token"),
+          'Content-Type':'multipart/form-data'
+        },
+        url: `/manage/file/upload`,
+      });
+      let url = result.data.urlPath;
+      console.log(url);
+      Editor.insertEmbed(
+        cursorLocation,
+        "image",
+        url
+      );
+      resetUploader();
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+</style>

+ 266 - 0
src/components/Tinymce/index.vue

@@ -0,0 +1,266 @@
+<template>
+  <div class="tinymce-container editor-container" :class="{fullscreen:fullscreen}">
+    <textarea :id="tinymceId" class="tinymce-textarea" />
+  </div>
+</template>
+
+<script>
+import plugins from "./plugins"; // 见下文
+import toolbar from "./toolbar"; // 见下文
+
+// 上传html片段接口根据自己项目更换
+// import { uploadHtml } from "@/api/upload";
+export default {
+  name: "Tinymce",
+  props: {
+    // 默认填充到富文本的html文件
+    htmlstr: {
+      type: String,
+      default: "",
+    },
+    toolbar: {
+      type: Array,
+      default() {
+        return [];
+      },
+    },
+    menubar: {
+      type: Boolean,
+      default: true,
+    },
+    height: {
+      type: Number,
+      default: 400,
+    },
+  },
+  data() {
+    return {
+      hasChange: false,
+      hasInit: false,
+      tinymceId: "vue-tinymce-" + +new Date(),
+      fullscreen: false,
+      value: "",
+      editorContent: "",
+    };
+  },
+  watch: {
+    value(val) {
+      this.$nextTick(() =>
+        window.tinymce.get(this.tinymceId).setContent(val || "")
+      );
+    },
+    htmlstr(val) {
+      this.value = val
+      if (this.isUrl) {
+        this.loadUrl(val);
+      }
+    },
+  },
+  created() {
+      this.value = this.htmlstr + "";
+      this.editorContent = this.htmlstr + "";
+  },
+  mounted() {
+    this.initTinymce();
+  },
+  activated() {
+    this.initTinymce();
+  },
+  deactivated() {
+    this.destroyTinymce();
+  },
+  destroyed() {
+    this.destroyTinymce();
+  },
+  methods: {
+    initTinymce() {
+      window.tinymce.init({
+        branding:false,
+        fontsize_formats: "12px 14px 16px 18px 20px 24px 36px",
+        language: "zh_CN",
+        language_url: "./static/tinymce/langs/zh_CN.js",
+        selector: `#${this.tinymceId}`,
+        height: this.height,
+        body_class: "panel-body ",
+        object_resizing: true,
+        toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
+        menubar: this.menubar,
+        plugins: plugins,
+        end_container_on_empty_block: true,
+        powerpaste_word_import: "clean",
+        paste_data_images:true,
+        code_dialog_height: 450,
+        code_dialog_width: 1000,
+        advlist_bullet_styles: "square",
+        advlist_number_styles: "default",
+        default_link_target: "_blank",
+        link_title: false,
+        file_picker_types:"file",
+        file_picker_callback:(cb,value,meta)=>{
+          console.log(cb,value,meta)          
+        },
+        file_upload_handler:async (blobInfo,success,failure)=>{
+          let form = new FormData()
+          console.log(blobInfo.file)
+          form.append('file',blobInfo.file)
+           await this.$http({
+            method: "post",
+            data: form,
+            headers: {
+              token: window.localStorage.getItem("token"),
+              'Content-Type':'multipart/form-data'
+            },
+            url: `/manage/file/upload`,
+          }).then(result=>{
+            let url = result.data.urlPath;
+            success(url)
+          }).catch(err=>{
+            failure(err)
+          })
+        },
+        images_upload_handler:async (blobInfo,success,failure)=>{
+          let form = new FormData()
+          console.log(failure)
+          form.append('file',blobInfo.blob(),blobInfo.filename())
+          await this.$http({
+            method: "post",
+            data: form,
+            headers: {
+              token: window.localStorage.getItem("token"),
+              'Content-Type':'multipart/form-data'
+            },
+            url: `/manage/file/upload`,
+          }).then(result=>{
+            let url = result.data.urlPath;
+            success(url)
+          }).catch(()=>{
+            this.$alert("上传失败,请稍后再试", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+                this.loading.close()
+              },
+            });
+          })
+        },
+        init_instance_callback: (editor) => {
+          if (this.value) {
+            editor.setContent(this.value);
+          }
+          this.hasInit = true;
+          editor.on("Blur", () => {
+            this.hasChange = true;
+            this.$emit("blur", editor.getContent());
+            this.editorContent = editor.getContent();
+          });
+        },
+        setup(editor) {
+          editor.on("FullscreenStateChanged", (e) => {
+            this.fullscreen = e.state;
+          });
+        },
+      });
+    },
+    destroyTinymce() {
+      if (window.tinymce.get(this.tinymceId)) {
+        window.tinymce.get(this.tinymceId).destroy();
+      }
+    },
+    loadUrl(url) {
+      this.editorContent = url
+      // if (url && url.length > 0) {
+      //   this.$http
+      //     .get(url)
+      //     .then((response) => {
+      //       // 处理HTML显示
+      //       this.value = response.data;
+      //       this.editorContent = response.data;
+      //       this.$emit("subLoadUrlToHtml", response.data);
+      //       this.$emit("input", response.data);
+      //     })
+      //     .catch(() => {
+      //       this.value = "服务器数据加载失败,请重试!";
+      //     });
+      // }
+    },
+    // 设置编辑器内容
+    setContent(value) {
+      window.tinymce.get(this.tinymceId).setContent(value);
+    },
+    // 获取编辑器内容
+    getContent() {
+      window.tinymce.get(this.tinymceId).getContent();
+    },
+    // 图片上传成功后填充到富文本编辑器
+    async imageSuccess(urlList) {
+      try {
+        let imageTemplateList = "";
+        urlList.forEach((item) => {
+          const image = `<img style="max-width:100%;" src="${item}">`;
+          imageTemplateList = imageTemplateList + image;
+        });
+        window.tinymce.get(this.tinymceId).insertContent(imageTemplateList);
+        this.$message({
+          message: "上传成功!",
+          type: "success",
+        });
+      } catch (error) {
+        console.log(error);
+        this.$message({
+          message: error,
+          type: "error",
+        });
+      }
+    },
+    // 编辑器内容上传到cos,调用返回url
+    // async content2Url() {
+    //   try {
+    //     const res = await uploadHtml(this.editorContent);
+    //     return res;
+    //   } catch (error) {
+    //     this.$message({
+    //       message: error.data.message,
+    //       type: "error",
+    //     });
+    //   }
+    // },
+  },
+};
+</script>
+<style lang="less" scoped>
+#tinymce {
+  background-color: blue;
+  p {
+    margin: 0;
+  }
+}
+.tinymce-container {
+  position: relative;
+}
+.tinymce-container{
+    /deep/ .mce-fullscreen {
+        z-index: 10000;
+    }
+}
+.tinymce-textarea {
+  visibility: hidden;
+  z-index: -1;
+}
+.editor-custom-btn-container {
+  position: absolute;
+  right: 4px;
+  top: 4px;
+  /*z-index: 2005;*/
+}
+.fullscreen .editor-custom-btn-container {
+  z-index: 10000;
+  position: fixed;
+}
+.editor-upload-btn {
+  display: inline-block;
+}
+// 隐藏底部logo栏
+.mce-edit-area + .mce-statusbar {
+  opacity: 0;
+  height: 0;
+}
+</style>

+ 5 - 0
src/components/Tinymce/plugins.js

@@ -0,0 +1,5 @@
+const plugins = [
+    'advlist anchor autolink autosave code indent2em lineheight codesample directionality emoticons fullscreen hr image imagetools importcss insertdatetime link lists media nonbreaking noneditable pagebreak  preview print save searchreplace tabfocus table template  textpattern visualblocks visualchars wordcount paste axupimgs'
+  ]
+  
+export default plugins

+ 3 - 0
src/components/Tinymce/toolbar.js

@@ -0,0 +1,3 @@
+const toolbar = ['formatselect fontsizeselect forecolor backcolor bold italic underline strikethrough alignleft aligncenter alignright outdent indent  indent2em lineheight  removeformat  hr undo redo image media axupimgs']
+
+export default toolbar

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

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

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

@@ -0,0 +1,86 @@
+<!--  -->
+<template>
+<div class='main-top'>
+  <crumbs :data="crumb" />
+  <div v-if="status" class="edit-status">{{`(${statusStr[status]})`}}</div>
+  <el-button v-if="questionBack"  type="primary" @click="backToQuestionList">返回</el-button>
+  <slot name='con'></slot>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import Crumbs from '../crumbs'
+
+export default {
+  
+// import引入的组件需要注入到对象中才能使用
+  props: {
+    crumb: {
+      default: () => [],
+      type: Array
+    },
+    status:{
+      default: 0,
+      type: Number
+    },
+    questionBack:{
+      default: false,
+      type: Boolean
+    },
+  },
+  components: {Crumbs},
+  data () {
+    // 这里存放数据
+    return {
+
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+    backToQuestionList(){
+      this.$router.push({path:'/questionnaire'})
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+<style lang="less" scoped>
+.main-top{
+  background:#fff;
+  width: 100%;
+  margin-bottom: 20px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding-right: 20px;
+  position: relative;
+  .edit-status{
+    position: absolute;
+    transform: translate(-50%,-50%);
+    left: 50%;
+    top: 50%;
+    letter-spacing: 3px;
+  }
+}
+
+</style>

+ 175 - 0
src/components/picture-upload/index.vue

@@ -0,0 +1,175 @@
+<!--  -->
+<template>
+  <div style="display: inline">
+    <el-upload
+      :headers="headerObj"
+      class="avatar-uploader"
+      :action="uploadUrl"
+      :show-file-list="false"
+      :on-success="handleAvatarSuccess"
+      :before-upload="beforeAvatarUpload"
+    >
+      <el-button
+        class="deleteIcon"
+        type="danger"
+        icon="el-icon-delete"
+        circle
+        size="mini"
+        @click.stop="delFile"
+        v-if="data.id"
+      ></el-button>
+      <img v-if="imageUrl" :src="imageUrl" class="avatar" />
+      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+
+      <el-button v-if="data.isIndex != 1 && data.id" type="primary" size="mini" @click.stop="setAsCover"
+        >设为封面</el-button
+      >
+      <el-button type="info" size="mini" @click.stop="uploadAgain">重新上传</el-button>
+    </el-upload>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import * as common from "@/util/commonfn.js";
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  props: {
+    data: {
+      default: () => {},
+      type: Object,
+    },
+  },
+  components: {},
+  data() {
+    // 这里存放数据
+    return {
+      imageUrl: "",
+      uploadUrl: `${this.$serverName}manage/exhibition/upload`,
+      headerObj: {
+        token: window.localStorage.getItem("token"),
+      },
+    };
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+    async delFile() {
+        console.log('删除文件',this.data);
+        let result = await this.$http({
+        method: "get",
+        url: `/manage/exhibition/remove/file/${this.data.id}`,
+      });
+      console.log("result", result);
+      if(result['code'] === 0) {
+          common.tip('success','删除成功')
+        //   让data为空更新视图
+          this.imageUrl = '';
+          this.$emit('emitRefresh',this.data.id)
+      }
+    },
+    async setAsCover(e) {
+      console.log('e',e)
+      console.log("设置为封面", this.data);
+        let result = await this.$http({
+        method: "get",
+        url: `/manage/exhibition/setIndex/${this.data.id}`,
+      });
+      console.log("result", result);
+      if(result['code'] === 0) {
+          common.tip('success','设置成功')
+          this.$emit('emitRefresh')
+      }
+    },
+    uploadAgain(e){
+        console.log('e',e);
+        console.log("重新上传", this.data);
+    },
+    handleAvatarSuccess(res, file) {
+      console.log("res", res);
+      console.log("file", file);
+      if (res["code"] === 0) {
+        this.$emit("emitFileId", res["data"]["id"]);
+        if (!this.uploadUrl.includes("?")) {
+          this.uploadUrl = `${this.uploadUrl}?code=${res["data"]["code"]}`;
+          this.$emit("emitCode", res["data"]["code"]);
+        }
+        this.imageUrl = URL.createObjectURL(file.raw);
+      } else {
+        common.tip("erroe", `${res.msg}!  上传失败,请联系管理员`);
+      }
+    },
+    beforeAvatarUpload(file) {
+      const isJPG = file.type === "image/jpeg" || "image/png";
+      const isLt2M = file.size / 1024 / 1024 < 2;
+
+      if (!isJPG) {
+        this.$message.error("上传头像图片只能是 JPG 格式!");
+      }
+      if (!isLt2M) {
+        this.$message.error("上传头像图片大小不能超过 2MB!");
+      }
+      return isJPG && isLt2M;
+    },
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    console.log("this.data", this.data);
+    this.imageUrl =
+      (this.data && this.data.ossUrl && `${this.OSSURL}${this.data.ossUrl}`) ||
+      "";
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, // 生命周期 - 创建之前
+  beforeMount() {}, // 生命周期 - 挂载之前
+  beforeUpdate() {}, // 生命周期 - 更新之前
+  updated() {
+  }, // 生命周期 - 更新之后
+  beforeDestroy() {}, // 生命周期 - 销毁之前
+  destroyed() {}, // 生命周期 - 销毁完成
+  activated() {}, // 如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style scoped>
+.avatar-uploader {
+  display: inline-block;
+  width: 23%;
+  margin: 1%;
+  position: relative;
+}
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+  border: 1px solid #d9d9d9;
+}
+.avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+
+.deleteIcon {
+  position: absolute;
+  top: 0;
+  right: 0;
+}
+</style>

+ 60 - 0
src/configue/base.js

@@ -0,0 +1,60 @@
+const base = {
+  reg: {
+    idCard: /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|[xX])$/,
+    phone: /^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$/,
+    email: /^([a-zA-Z0-9]+[_|_|.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|_|.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/
+  },
+  isImg: function (url) {
+    var temp = []
+    temp = url.toString().split('.')
+    if (temp[temp.length - 1].toLowerCase() === 'png' || temp[temp.length - 1].toLowerCase() === 'jpg') {
+      return true
+    } else {
+      return false
+    }
+  },
+  timestampToTime: function (timestamp) {
+    var date = new Date(Number(timestamp))// 时间戳为10位需*1000,时间戳为13位的话不需乘1000
+
+    var Y = date.getFullYear() + '-'
+
+    var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'
+
+    var D = date.getDate() + ' '
+
+    // var h = date.getHours() + ':'
+
+    // var m = date.getMinutes() + ':'
+
+    // var s = date.getSeconds()
+
+    return Y + M + D
+  },
+  dateFormat: function (fmt, that) {
+    var o = {
+      'M+': that.getMonth() + 1, // 月份
+      'd+': that.getDate(), // 日
+      'h+': that.getHours(), // 小时
+      'm+': that.getMinutes(), // 分
+      's+': that.getSeconds(), // 秒
+      'q+': Math.floor((that.getMonth() + 3) / 3), // 季度
+      S: that.getMilliseconds() // 毫秒
+    }
+    if (/(y+)/.test(fmt)) {
+      fmt = fmt.replace(
+        RegExp.$1,
+        (that.getFullYear() + '').substr(4 - RegExp.$1.length)
+      )
+    }
+    for (var k in o) {
+      if (new RegExp('(' + k + ')').test(fmt)) {
+        fmt = fmt.replace(
+          RegExp.$1,
+          RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
+        )
+      }
+    }
+    return fmt
+  }
+}
+export { base }

+ 3 - 0
src/configue/bus.js

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

+ 151 - 0
src/configue/http.js

@@ -0,0 +1,151 @@
+import axios from 'axios'
+// import qs from 'qs'
+import Vue from 'vue'
+import router from '../router'
+
+const vue = new Vue()
+
+var isProduction = process.env.NODE_ENV === 'production'
+let loading = ''
+
+// 不校验token的api
+const notTokenApis = ['/admin/login']
+// 配置请求域名
+// const serverName = 'http://192.168.0.135:8001/'
+const serverName = isProduction ? 'http://8.135.106.227:8001/' : 'http://8.135.106.227:8001/'
+// http://192.168.0.44:8100/web/index.html#/
+
+const serverLocation = window.location.hostname
+
+axios.defaults.baseURL = serverName
+axios.defaults.headers['X-Requested-with'] = 'XMLHttpRequest'
+// axios.defaults.headers['token'] =  window.localStorage.getItem('token')
+const expectUrls = ['/manage/file/upload']
+
+axios.interceptors.request.use(function (config) {
+  const token = localStorage.getItem('token')
+  if (token) {
+    config.headers['token'] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
+  } 
+  else if(notTokenApis.includes(config.url)) {
+    console.log('不用token校验的api')
+  }
+  else{
+    vue.$alert('登录状态失效,请重新登录', '提示', {
+      confirmButtonText: '确定',
+      callback: function () {
+        window.localStorage.setItem('userInfo', '')
+        router.push('/login')
+      }
+    })
+    return
+  }
+  loading = vue.$loading({
+    lock: true,
+    text: '加载中',
+    spinner: 'el-icon-loading',
+    background: 'rgba(0, 0, 0, 0.7)'
+  });
+  for (let i = 0; i < expectUrls.length; i++) {
+    const element = expectUrls[i];
+    if(element == config.url){
+      return config
+    }
+  }
+  if (config.method === 'post') {
+    config.data = {
+      ...config.data,
+      rnd: Math.random()
+    }
+    // config.data = qs.stringify(config.data)
+  } else if (config.method === 'get') {
+    config.params = {
+      rnd: Math.random(),
+      ...config.params
+    }
+    // config.params = qs.stringify(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)
+    loading.close()
+    switch (code) {
+      case -1:
+        break
+        case 4500:
+          vue.$alert('没有获得授权,请联系系统管理员', '提示', {
+            confirmButtonText: '确定',
+            callback: function () {
+            }
+          })
+          break
+        case 5001:
+
+          if (window.localStorage.getItem('token')) {
+            window.localStorage.setItem('token', '')
+            vue.$alert('登录状态失效,请重新登录', '提示', {
+              confirmButtonText: '确定',
+              callback: function () {
+                window.localStorage.setItem('userInfo', '')
+                router.push('/login')
+              }
+            })
+          }
+          else{
+            vue.$alert('登录状态失效,请重新登录', '提示', {
+              confirmButtonText: '确定',
+              callback: function () {
+                window.localStorage.setItem('userInfo', '')
+                router.push('/login')
+              }
+            })
+          }
+          break
+        case 5002:
+          if (window.localStorage.getItem('token')) {
+            window.localStorage.setItem('token', '')
+            vue.$alert('登录状态失效,请重新登录', '提示', {
+              confirmButtonText: '确定',
+              callback: function () {
+                window.localStorage.setItem('userInfo', '')
+                router.push('/login')
+              }
+            })
+          }
+          break
+        case 500:
+          vue.$alert(data.message || '服务器错误', '提示', {
+            confirmButtonText: '确定',
+            callback: function () {
+            }
+          })
+          break
+      case 0:
+        break
+    }
+    // tryHideFullScreenLoading()
+    return data
+  },
+  error => {
+    loading.close()
+    if (error.response) {
+      let data = error.response.data
+      vue.$alert(data.msg||'服务器错误,请稍后再试', '提示', {
+        confirmButtonText: '确定',
+        callback: function () {
+        }
+      })
+    }
+    return Promise.reject(error)
+  }
+)
+export { serverName, axios, serverLocation }

+ 12 - 0
src/filters/index.js

@@ -0,0 +1,12 @@
+export const getDicValue = function(val,dictionary){
+    let result = "";
+    if(!val || !dictionary) {
+        return result;
+    }
+    let targetArr = dictionary.filter(item=>item.id === val);
+    let arrStr = [];
+    targetArr.forEach(item=>{
+        arrStr.push(item.name)
+    })
+    return arrStr.join(',')
+}

+ 151 - 0
src/main.js

@@ -0,0 +1,151 @@
+import Vue from 'vue'
+import App from './App.vue'
+import router from './router'
+import ElementUI from 'element-ui';
+import {base} from '@/configue/base'
+import 'element-ui/lib/theme-chalk/index.css';
+import {axios, serverName} from './configue/http'
+import '../theme/index.css'
+import {isImage,isTypeBySend} from "@/util/index.js";
+//全局过滤器
+import * as filters from '@/filters/index.js'
+Object.keys(filters).forEach(key=>{
+  Vue.filter(key,filters[key])//插入过滤器名和对应方法
+})
+
+//弹框
+import layer from 'vue-layer'
+import 'vue-layer/lib/vue-layer.css';
+Vue.prototype.$layer = layer(Vue);
+
+//富文本
+import VueQuillEditor from 'vue-quill-editor'
+ 
+// require styles
+import 'quill/dist/quill.core.css'
+import 'quill/dist/quill.snow.css'
+import 'quill/dist/quill.bubble.css'
+ 
+Vue.use(VueQuillEditor, /* { default global options } */)
+
+Vue.use(ElementUI)
+Vue.config.productionTip = false
+
+Vue.prototype.$base = base
+Vue.prototype.$bus = new Vue()
+Vue.prototype.$http = axios
+Vue.prototype.isImage = isImage
+Vue.prototype.isTypeBySend = isTypeBySend
+Vue.prototype.OSSURL = "https://oss-xiaoan.oss-cn-shenzhen.aliyuncs.com/"
+
+Vue.prototype.MAXLENGTH = 200
+Vue.prototype.FONTLENGTH = 25
+Vue.prototype.PAGESIZES = [25,50,75,100]
+Vue.prototype.loading = {
+  close(){
+
+  }
+}
+
+
+Vue.prototype.loadOption = {
+  lock: true,
+  text: '上传中',
+  spinner: 'el-icon-loading',
+  background: 'rgba(0, 0, 0, 0.7)'
+}
+
+
+Vue.prototype.statusStr = {
+  1: "草稿中",
+  2: "待审核",
+  3: "审核不通过",
+  4: "审核通过"
+};
+
+
+let tmpYear = []
+for (let i = 2000; i <= 2050; i++) {
+  tmpYear.push({
+    id:i,
+    name:i+'年'
+  })
+}
+
+Vue.prototype.yearStr = [
+  {
+    id:1001,
+    name:'革命战争时期'
+  },
+  {
+    id:1002,
+    name:'和平建设时期'
+  },
+  {
+    id:1003,
+    name:'军区联勤时期'
+  }
+].concat(tmpYear);
+
+
+Vue.prototype.typeStr = {
+  news: "新闻",
+  notice: "公告"
+};
+
+
+Vue.prototype.statusArr = [
+  {
+    id:1,
+    name:'草稿中'
+  },
+  {
+    id:2,
+    name:'待审核'
+  },
+  {
+    id:3,
+    name:'审核不通过'
+  },
+  {
+    id:4,
+    name:'审核通过'
+  }
+]
+
+Vue.prototype.sysRole=[
+  {
+    name:'系统管理员',
+    id:'sys_admin'
+  },
+  {
+    name:'普通用户',
+    id:'sys_normal'
+  },
+]
+
+Vue.prototype.collectType = {
+  1:'专题图库',
+  2:'视频文件',
+  3:'模型文件'
+};
+
+
+Vue.prototype.juese = {
+  sys_admin: "系统管理员",
+  sys_high: "高级管理员",
+  sys_normal: "普通用户",
+  sys_visitor: "游客",
+};
+
+Vue.prototype.sex = {
+  0: "男",
+  1: "女"
+};
+
+Vue.prototype.$serverName = serverName// 挂载到Vue实例上面
+
+new Vue({
+  router,
+  render: h => h(App)
+}).$mount('#app')

+ 149 - 0
src/pages/activity/activityEdit.vue

@@ -0,0 +1,149 @@
+<template>
+  <div class="Root">
+    <el-form
+      :model="form"
+      :rules="rules"
+      ref="form"
+      label-width="100px"
+      class="demo-ruleForm"
+    >
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="标题" prop="name" maxlength="30">
+            <el-input v-model="form.name"></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="类别" prop="type">
+            <el-select v-model="form.type" placeholder="请选择类别">
+              <el-option label="线上活动" value="online"></el-option>
+              <el-option label="志愿者服务" value="volunteer"></el-option>
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row style="margin-bottom: 100px">
+        <el-col :span="24">
+          <el-form-item label="内容" prop="content" maxlength="30">
+            <vue-editor class="quill-editor" v-model="form.content" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="24">
+          <el-form-item>
+            <el-button type="primary" @click="submitForm('form')"
+              >保存</el-button
+            >
+            <el-button @click="quxiao()">取消</el-button>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import { VueEditor} from "vue2-editor";
+import * as common from "@/util/commonfn.js";
+export default {
+  components: {
+    VueEditor
+  },
+  data() {
+    return {
+      headerObj: {
+        token: window.localStorage.getItem("token"),
+      },
+      fileList: [],
+      form: {
+        name: "",
+        content: "",
+        type: "",
+      },
+      rules: {
+        name: [{ required: true, message: "请输入标题", trigger: "blur"},{max: 30,message: "不能超过30个字符"}],
+        type: [{ required: true, message: "请选择类别", trigger: "blur" }],
+        content: [{ required: true, message: "请输入内容", trigger: "blur" }],
+      },
+      uploadUrl: `${this.$serverName}manage/activity/upload`,
+    };
+  },
+  props: {
+    layerid: {
+      //自动注入的layerid
+      type: String,
+      default: "",
+    },
+    iframeData: {
+      //传递的数据
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+  },
+  methods: {
+    quxiao(reload) {
+      this.$layer.close(this.layerid);
+      //点击取消 不刷新列表   点击确认 保存成功刷新列表
+      if (reload) {
+        this.$parent.getInformation();
+      }
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.save();
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    async save() {
+      let { content, name, type, id,code } = this.form;
+      let data = { content, name, type, id,code };
+      let result = await this.$http({
+        method: "post",
+        data,
+        url: `/manage/activity/save`,
+      });
+      if (result["code"] === 0) {
+        common.tip("success", "保存成功");
+        this.quxiao(true);
+      } else {
+        common.tip("error", "保存失败,请联系管理员");
+      }
+    },
+  },
+  watch: {
+    iframeData: {
+      handler: function () {
+        this.form = this.iframeData;
+      },
+      deep: true,
+      immediate: true,
+    },
+  },
+  created() {
+    // code 来区分文件
+    if (this.form["code"]) {
+      this.uploadUrl = `${this.uploadUrl}?code=${this.form["code"]}`;
+    }
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.quill-editor {
+    line-height: normal;
+}
+.Root {
+  padding: 50px;
+}
+.ivu-upload {
+  display: none;
+}
+</style>
+

+ 270 - 0
src/pages/activity/activityList.vue

@@ -0,0 +1,270 @@
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span>类别:</span>
+            <el-select v-model="params.type" placeholder="请选择类别">
+              <el-option label="全部" value=""></el-option>
+              <el-option
+                v-for="item in activitySort"
+                :key="item.id"
+                :label="item.name"
+                :value="item.id"
+              >
+              </el-option>
+            </el-select>
+            &nbsp;
+            <span>关键字:</span>
+            <el-input
+              class="elInput"
+              v-model="params.searchKey"
+              placeholder="请输入关键字"
+            ></el-input>
+
+            <el-button
+              style="margin-left: 1.25rem"
+              type="primary"
+              @click="getInformation(true)"
+              >查询</el-button
+            >
+            <el-button type="primary" @click="edit({}, 'add')">新增</el-button>
+          </div>
+          <div class="info-right"></div>
+        </div>
+        <el-table
+          :data="tableData"
+          height="61vh"
+          class="collection-con"
+          :tree-props="{ children: 'children' }"
+          row-key="id"
+          style="width: 100%"
+        >
+          <el-table-column
+            type="index"
+            label="序号"
+            :index="indexMethod"
+          ></el-table-column>
+          <el-table-column prop="name" label="文章标题"></el-table-column>
+          <el-table-column prop="type" label="活动分类">
+            <template slot-scope="scope">
+              {{ scope.row.type | getDicValue(activitySort) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="userName" label="发布用户"></el-table-column>
+          <el-table-column prop="createTime" label="发布时间"></el-table-column>
+          <el-table-column label="置顶">
+            <template slot-scope="scope">
+              <el-switch
+                v-model="scope.row.isIndex" :active-value="1" :inactive-value="0"
+                @change="switchChange(scope.row)"
+              >
+              </el-switch>
+            </template>
+          </el-table-column>
+
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span
+                class="o-span"
+                v-if="$role == 'sys_admin' || $role == 'sys_high'"
+                @click="edit(scope.row, 'edit')"
+                >编辑</span
+              >
+              <span
+                class="o-span"
+                v-if="
+                  scope.row.isIndex != '1' &&
+                  ($role == 'sys_admin' || $role == 'sys_high')
+                "
+                @click="del(scope.row)"
+                >删除</span
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="params.pageNum"
+            @size-change="handleSizeChange"
+            :page-size="params.pageSize"
+            :page-sizes="[10, 20, 50]"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import MainTop from "@/components/main-top";
+import activityEdit from "@/pages/activity/activityEdit";
+import * as common from "@/util/commonfn.js";
+
+const crumbData = [
+  {
+    name: "活动资讯",
+    id: 5 - 1,
+  },
+];
+
+export default {
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      activitySort: [],
+      crumbData,
+      tableData: [],
+      params: {
+        pageNum: 1,
+        pageSize: 10,
+        searchKey: "",
+        type: "",
+      },
+      total: 0,
+    };
+  },
+  computed: {},
+  watch: {},
+  created() {
+    this.getInformation();
+    this.getActivitySort();
+  },
+  mounted() {},
+
+  methods: {
+    indexMethod(index) {
+      return (this.params.pageNum - 1) * this.params.pageSize + index + 1;
+    },
+    edit(item = {}, type) {
+      //单独处理display
+      item = { ...item, display: item.display ? true : false };
+      this.$layer.iframe({
+        content: {
+          content: activityEdit,
+          parent: this,
+          data: { iframeData: item },
+        },
+        area: ["900px", "600px"],
+        title: `${type === "add" ? "新增" : "编辑"}活动资讯`,
+        maxmin: false,
+        shade: false,
+        shadeClose: false,
+        cancel: () => {
+          //关闭弹窗事件
+          this.getInformation();
+        },
+      });
+    },
+    del(item) {
+      this.$confirm("是否确认删除这个藏品信息?", "提示", {
+        confirmButtonText: "是",
+        cancelButtonText: "否",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http.get(`/manage/goods/remove/${item.id}`, {}).then((res) => {
+            if (res.code === 0) {
+              this.$alert("删除成功", "提示", {
+                confirmButtonText: "确定",
+                callback: () => {
+                  this.getInformation();
+                },
+              });
+            } else {
+              this.$notify.error({
+                title: "错误",
+                message: res.msg,
+              });
+            }
+          });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    handleCurrentChange(val) {
+      this.params.pageNum = val;
+      this.getInformation();
+    },
+    handleSizeChange(val) {
+      this.params.pageSize = val;
+      this.getInformation();
+    },
+    async getInformation(reload = false) {
+      if (reload) {
+        this.params.pageNum = 1;
+        this.tableData = [];
+      }
+      let result = await this.$http({
+        method: "post",
+        data: this.params,
+        url: "/manage/activity/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.tableData = result.data.list
+      this.total = result.data.total;
+    },
+    async getActivitySort() {
+      this.activitySort = [
+        { id: "online", name: "线上活动" },
+        { id: "volunteer", name: "志愿者服务" },
+      ];
+    },
+    switchChange(item) {
+      this.top(item);
+    },
+    async top(item={}) {
+      let result = await this.$http({
+        method: "get",
+        url: `/manage/activity/setIndex/${item.id}`
+      });
+      if (result.code == 0) {
+        common.tip("success", "置顶成功");
+        this.getInformation();
+      } else {
+        common.tip("error", "置顶失败,请联系管理员");
+      }
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow: auto;
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+</style>
+

+ 324 - 0
src/pages/collection/collectionEdit.vue

@@ -0,0 +1,324 @@
+<template>
+  <div class="Root">
+    <el-form
+      :model="ruleForm"
+      :rules="rules"
+      ref="ruleForm"
+      label-width="100px"
+      class="demo-ruleForm"
+    >
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="藏品名称" prop="name">
+            <el-input
+              v-model="ruleForm.name"
+              placeholder="请输入藏品名称"
+              maxlength="15"
+            ></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="11">
+          <el-form-item prop="goodsTypeId" label="藏品分类">
+            <el-select v-model="ruleForm.goodsTypeId" placeholder="请选择类别">
+              <el-option
+                v-for="item in collectionSort"
+                :key="item.id"
+                :label="item.name"
+                :value="item.id"
+              >
+              </el-option>
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="11">
+          <el-form-item prop="goodsAgeId" label="年代">
+            <el-select v-model="ruleForm.goodsAgeId" placeholder="请选择年代">
+              <el-option
+                v-for="item in collectionYears"
+                :key="item.id"
+                :label="item.name"
+                :value="item.id"
+              >
+              </el-option>
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-col :span="11">
+          <el-form-item prop="type" label="藏品形式">
+            <el-select
+              v-model="ruleForm.type"
+              placeholder="请选择藏品形式"
+            >
+              <el-option
+                v-for="item in typeList"
+                :key="item.id"
+                :label="item.name"
+                :value="item.value"
+              >
+              </el-option>
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="11" v-if="ruleForm.type === 'model'">
+          <el-form-item label="3D模型" prop="modelUrl">
+            <el-input
+              v-model="ruleForm.modelUrl"
+              placeholder="请输入3D模型"
+            ></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-form-item label="藏品图片">
+          <el-upload
+            class="avatar-uploader"
+            ref="upload"
+            accept=".jpg,.png"
+            :headers="headerObj"
+            :action="uploadUrl"
+            :on-error="handleError"
+            :show-file-list="false"
+            :on-success="handleIconSuccess"
+            :before-upload="beforeIconUpload"
+            :on-change="handleChange"
+            :on-remove="handleRemove"
+          >
+            <img
+              v-if="ruleForm.thumb"
+              :src="OSSURL + ruleForm.thumb"
+              class="avatar"
+            />
+            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+            <!-- 单纯用来刷新视图的变化的 -->
+            <el-input v-show="false" v-model="refresh"></el-input>
+          </el-upload>
+          <div>
+            <p style="color: #999">格式要求:</p>
+            <p style="color: #999; line-height: 1">1、支持png,jpeg的图片格式</p>
+            <p style="color: #999">2、最大可支持10M</p>
+          </div>
+        </el-form-item>
+      </el-row>
+      <el-row>
+        <el-form-item label="藏品介绍" prop="description">
+          <vue-editor class="quill-editor" v-model="ruleForm.description" />
+        </el-form-item>
+      </el-row>
+      
+      <el-row>
+        <el-form-item>
+          <el-button type="primary" @click="submitForm('ruleForm')"
+            >保存</el-button
+          >
+          <el-button @click="quxiao()">取消</el-button>
+        </el-form-item>
+      </el-row>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import * as common from "@/util/commonfn.js";
+import { VueEditor } from "vue2-editor";
+export default {
+  components: {
+    VueEditor,
+  },
+  data() {
+    return {
+      refresh: "未刷新",
+      headerObj: {
+        token: window.localStorage.getItem("token"),
+      },
+      ruleForm: {
+        goodsTypeId: "",
+        display: 0,
+      },
+      rules: {
+        name: [{ required: true, message: "请输入藏品名称", trigger: "blur" }],
+        goodsTypeId: [
+          { required: true, message: "请选择藏品分类", trigger: "blur" },
+        ],
+        goodsAgeId: [{ required: true, message: "请选择年代", trigger: "blur" }],
+        description: [
+          { required: true, message: "请输入藏品介绍", trigger: "blur" },
+        ],
+        modelUrl: [
+          { required: true, message: "请输入3D模型", trigger: "blur" },
+        ],
+        type:[{ required: true, message: "请选择藏品形式", trigger: "blur" }]
+      },
+      token: window.localStorage.getItem("token"),
+      uploadUrl: `${this.$serverName}manage/goods/upload`,
+      fileList: [],
+      collectionSort: [],
+      collectionYears: [],
+      typeList: [
+        { id: 0, name: "图片", value:"img" },
+        { id: 1, name: "三维", value:"model" },
+      ],
+    };
+  },
+  props: {
+    layerid: {
+      //自动注入的layerid
+      type: String,
+      default: "",
+    },
+    iframeData: {
+      //传递的数据
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+  },
+  methods: {
+    quxiao(reload) {
+      this.$layer.close(this.layerid);
+      //点击取消 不刷新列表   点击确认 保存成功刷新列表
+      if (reload) {
+        this.$parent.getInformation();
+      }
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          if (!this["ruleForm"].thumb) {
+            common.tip("warning", "请上传图片");
+            return;
+          }
+          this.save();
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    async save() {
+      let {
+        name,
+        id,
+        goodsTypeId,
+        description,
+        modelUrl,
+        thumb,
+        type,
+        goodsAgeId
+      } = this.ruleForm;
+      let data = {
+        name,
+        id,
+        goodsTypeId,
+        description,
+        modelUrl,
+        thumb,
+        type,
+        goodsAgeId
+      };
+      let result = await this.$http({
+        method: "post",
+        data,
+        url: `/manage/goods/save`,
+      });
+      if (result["code"] === 0) {
+        common.tip("success", "保存成功");
+        this.quxiao(true);
+      } else {
+        common.tip("error", "保存失败,请联系管理员");
+      }
+    },
+    handleError() {},
+    handleIconSuccess(res) {
+      let { data } = res;
+      this.ruleForm.thumb = data.ossPath;
+      // 刷新下页面
+      this.refresh = "刷新了";
+    },
+    beforeIconUpload(file) {
+      let size = 10;
+      const isLt = file.size / 1024 / 1024 < size;
+      if (!isLt) {
+        this.$message.error(`上传头像图片大小不能超过 ${size}MB!`);
+        return isLt;
+      }
+    },
+    handleChange(file) {
+      this.fileList = this.fileList.length === 0 ? this.fileList : [];
+      this.fileList.push(file["raw"]);
+    },
+    handleRemove(file) {
+      let index = this.fileList.findIndex((item) => {
+        return item.uid === file.uid;
+      });
+      this.fileList.splice(index, 1);
+    },
+    async getCollectionSort() {
+      let result = await this.$http({
+        method: "get",
+        url: "/manage/goodsType/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.collectionSort = result.data;
+    },
+    async getCollectionYear() {
+      let result = await this.$http({
+        method: "get",
+        url: "/manage/goodsAge/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.collectionYears = result.data;
+    },
+  },
+  watch: {
+    iframeData: {
+      handler: function () {
+        this.ruleForm = this.iframeData;
+      },
+      deep: true,
+      immediate: true,
+    },
+  },
+  created() {
+    this.getCollectionSort();
+    this.getCollectionYear();
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.Root {
+  padding: 50px;
+}
+
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+  border: 1px dashed #d9d9d9;
+}
+</style>
+

+ 264 - 0
src/pages/collection/collectionList.vue

@@ -0,0 +1,264 @@
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span>类别:</span>
+            <el-select v-model="params.goodsTypeId" placeholder="请选择类别">
+              <el-option label="全部" value=""></el-option>
+              <el-option
+                v-for="item in collectionSort"
+                :key="item.id"
+                :label="item.name"
+                :value="item.id"
+              >
+              </el-option>
+            </el-select>
+            &nbsp;
+            <span>关键字:</span>
+            <el-input
+              class="elInput"
+              v-model="params.searchKey"
+              placeholder="请输入关键字"
+            ></el-input>
+
+            <el-button
+              style="margin-left: 1.25rem"
+              type="primary"
+              @click="getInformation(true)"
+              >查询</el-button
+            >
+            <el-button type="primary" @click="edit({}, 'add')">新增</el-button>
+          </div>
+          <div class="info-right"></div>
+        </div>
+        <el-table
+          :data="tableData"
+          height="61vh"
+          class="collection-con"
+          :tree-props="{ children: 'children' }"
+          row-key="id"
+          style="width: 100%"
+        >
+          <el-table-column
+            type="index"
+            label="序号"
+            :index="indexMethod"
+          ></el-table-column>
+          <el-table-column prop="name" label="藏品名称"></el-table-column>
+          <el-table-column prop="goodsTypeId" label="分类">
+            <template slot-scope="scope">
+              {{ scope.row.goodsTypeId | getDicValue(collectionSort) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="userName" label="发布用户"></el-table-column>
+          <el-table-column prop="createTime" label="发布时间"></el-table-column>
+
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span
+                class="o-span"
+                v-if="$role == 'sys_admin' || $role == 'sys_high'"
+                @click="edit(scope.row, 'edit')"
+                >编辑</span
+              >
+              <span
+                class="o-span"
+                v-if="
+                  scope.row.isIndex != '1' &&
+                  ($role == 'sys_admin' || $role == 'sys_high')
+                "
+                @click="del(scope.row)"
+                >删除</span
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="params.pageNum"
+            @size-change="handleSizeChange"
+            :page-size="params.pageSize"
+            :page-sizes="[10, 20, 50]"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import MainTop from "@/components/main-top";
+import collectionEdit from "@/pages/collection/collectionEdit";
+
+const crumbData = [
+  {
+    name: "藏品信息",
+    id: 4 - 2,
+  },
+];
+
+export default {
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      collectionSort: [],
+      collectionAge: [],
+      crumbData,
+      tableData: [],
+      params: {
+        pageNum: 1,
+        pageSize: 10,
+        searchKey: "",
+        goodsTypeId: "",
+      },
+      total: 0,
+    };
+  },
+  computed: {},
+  watch: {},
+  created() {
+    this.getInformation();
+    this.getCollectionSort();
+    this.getCollectionAge();
+  },
+  mounted() {},
+
+  methods: {
+    indexMethod(index) {
+      return (this.params.pageNum - 1) * this.params.pageSize + index + 1;
+    },
+    edit(item = {}, type) {
+      console.log("item", item);
+      //单独处理display
+      item = { ...item, display: item.display ? true : false };
+      this.$layer.iframe({
+        content: {
+          content: collectionEdit,
+          parent: this,
+          data: { iframeData: item },
+        },
+        area: ["900px", "600px"],
+        title: `${type === "add" ? "新增" : "编辑"}藏品信息`,
+        maxmin: false,
+        shade: false,
+        shadeClose: false,
+        cancel: () => {
+          //关闭弹窗事件
+          this.getInformation();
+        },
+      });
+    },
+    del(item) {
+      this.$confirm("是否确认删除这个藏品信息?", "提示", {
+        confirmButtonText: "是",
+        cancelButtonText: "否",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http.get(`/manage/goods/remove/${item.id}`, {}).then((res) => {
+            if (res.code === 0) {
+              this.$alert("删除成功", "提示", {
+                confirmButtonText: "确定",
+                callback: () => {
+                  this.getInformation();
+                },
+              });
+            } else {
+              this.$notify.error({
+                title: "错误",
+                message: res.msg,
+              });
+            }
+          });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    handleCurrentChange(val) {
+      this.params.pageNum = val;
+      this.getInformation();
+    },
+    handleSizeChange(val) {
+      this.params.pageSize = val;
+      this.getInformation();
+    },
+    async getInformation(reload = false) {
+      if (reload) {
+        this.params.pageNum = 1;
+        this.tableData = [];
+      }
+      let result = await this.$http({
+        method: "post",
+        data: this.params,
+        url: "/manage/goods/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.tableData = result.data.list;
+      this.total = result.data.total;
+    },
+    async getCollectionSort() {
+      let result = await this.$http({
+        method: "get",
+        url: "/manage/goodsType/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.collectionSort = result.data;
+      console.log(" this.collectionSort", this.collectionSort);
+    },
+    async getCollectionAge() {
+      let result = await this.$http({
+        method: "get",
+        url: "/manage/goodsAge/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.collectionAge = result.data;
+      console.log(" this.collectionAge", this.collectionAge);
+    }
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow: auto;
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+</style>
+

+ 116 - 0
src/pages/collection/collectionSortEdit.vue

@@ -0,0 +1,116 @@
+<template>
+  <div class="Root">
+    <el-form
+      :model="form"
+      :rules="rules"
+      ref="form"
+      label-width="100px"
+      class="demo-ruleForm"
+    >
+
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="分类名称" prop="name" maxlength="10">
+            <el-input v-model="form.name"></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-col :span="24">
+          <el-form-item>
+            <el-button type="primary" @click="submitForm('form')"
+              >保存</el-button
+            >
+            <el-button @click="quxiao()">取消</el-button>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+    </el-form>
+  </div>
+</template>
+
+<script>
+import * as common from "@/util/commonfn.js";
+export default {
+  data() {
+    return {
+      form: {
+        name: "",
+      },
+      rules: {
+        name: [{ required: true, message: "请输入分类名称", trigger: "blur" }],
+      },
+    };
+  },
+  props: {
+    layerid: {
+      //自动注入的layerid
+      type: String,
+      default: "",
+    },
+    iframeData: {
+      //传递的数据
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+  },
+  methods: {
+    quxiao(reload) {
+      this.$layer.close(this.layerid);
+      //点击取消 不刷新列表   点击确认 保存成功刷新列表
+      if (reload) {
+        this.$parent.getInformation();
+      }
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.save();
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    async save() {
+      let { name, id } = this.form;
+      let data = { name, id };
+      let result = await this.$http({
+        method: "post",
+        data,
+        url: `/manage/goodsType/save`,
+      });
+      if (result["code"] === 0) {
+        common.tip("success", "保存成功");
+        this.quxiao(true);
+      } else {
+        common.tip("error", "保存失败,请联系管理员");
+      }
+    },
+  },
+  watch: {
+    iframeData: {
+      handler: function () {
+        this.form = this.iframeData;
+      },
+      deep: true,
+      immediate: true,
+    },
+  },
+  created() {},
+};
+</script>
+
+<style lang="less" scoped>
+.Root {
+  padding: 50px;
+}
+.ivu-upload {
+  display: none;
+}
+</style>
+

+ 203 - 0
src/pages/collection/collectionSortList.vue

@@ -0,0 +1,203 @@
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <el-button type="primary" @click="edit({}, 'add')">新增</el-button>
+          </div>
+          <div class="info-right"></div>
+        </div>
+        <el-table
+          :data="tableData"
+          height="61vh"
+          class="collection-con"
+          :tree-props="{ children: 'children' }"
+          row-key="id"
+          style="width: 100%"
+        >
+          <el-table-column
+            type="index"
+            label="序号"
+            :index="indexMethod"
+          ></el-table-column>
+          <el-table-column prop="name" label="分类名称"></el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span
+                class="o-span"
+                v-if="$role == 'sys_admin'"
+                @click="edit(scope.row, 'edit')"
+                >编辑</span
+              >
+              <span
+                class="o-span"
+                v-if="
+                  ($role == 'sys_admin')
+                "
+                @click="del(scope.row)"
+                >删除</span
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="params.pageNum"
+            @size-change="handleSizeChange"
+            :page-size="params.pageSize"
+            :page-sizes="[10, 20, 50]"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+
+import MainTop from "@/components/main-top";
+import collectionSortEdit from "@/pages/collection/collectionSortEdit";
+
+const crumbData = [
+  {
+    name: "藏品分类",
+    id: 4 - 1,
+  },
+];
+
+export default {
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      crumbData,
+      tableData: [],
+      params: {
+        pageNum: 1,
+        pageSize: 10
+      },
+      total: 0
+    };
+  },
+  computed: {},
+  watch: {},
+  created() {
+    this.getInformation();
+  },
+  mounted() {},
+
+  methods: {
+    indexMethod(index) {
+      return (this.params.pageNum - 1) * this.params.pageSize + index + 1;
+    },
+    edit(item = {}, type) {
+      this.$layer.iframe({
+        content: {
+          content: collectionSortEdit,
+          parent: this,
+          data: { iframeData: item },
+        },
+        area: ["900px", "600px"],
+        title: `${type === "add" ? "新增" : "编辑"}藏品分类`,
+        maxmin: false,
+        shade: false,
+        shadeClose: false,
+        cancel: () => {
+          //关闭弹窗事件
+          this.getInformation()
+        },
+      });
+    },
+    del(item) {
+      this.$confirm("是否确认删除这个藏品分类?", "提示", {
+        confirmButtonText: "是",
+        cancelButtonText: "否",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http
+            .get(`/manage/goodsType/remove/${item.id}`, {})
+            .then((res) => 
+            
+            {
+              if (res.code === 0) {
+                this.$alert("删除成功", "提示", {
+                  confirmButtonText: "确定",
+                  callback: () => {
+                    this.getInformation();
+                  },
+                });
+              } else {
+                this.$notify.error({
+                  title: "错误",
+                  message: res.msg,
+                });
+              }
+            });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    handleCurrentChange(val) {
+      this.params.pageNum = val;
+      this.getInformation();
+    },
+    handleSizeChange(val) {
+      this.params.pageSize = val;
+      this.getInformation();
+    },
+    async getInformation(reload = false) {
+      if (reload) {
+        this.params.pageNum = 1;
+        this.tableData = [];
+      }
+      let result = await this.$http({
+        method: "get",
+        url: "/manage/goodsType/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.tableData = result.data;
+      this.total = result.data.length;
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow: auto;
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+</style>
+

+ 116 - 0
src/pages/collection/collectionYearEdit.vue

@@ -0,0 +1,116 @@
+<template>
+  <div class="Root">
+    <el-form
+      :model="form"
+      :rules="rules"
+      ref="form"
+      label-width="100px"
+      class="demo-ruleForm"
+    >
+
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="年代名称" prop="name" maxlength="10">
+            <el-input v-model="form.name"></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-col :span="24">
+          <el-form-item>
+            <el-button type="primary" @click="submitForm('form')"
+              >保存</el-button
+            >
+            <el-button @click="quxiao()">取消</el-button>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+    </el-form>
+  </div>
+</template>
+
+<script>
+import * as common from "@/util/commonfn.js";
+export default {
+  data() {
+    return {
+      form: {
+        name: "",
+      },
+      rules: {
+        name: [{ required: true, message: "请输入年代名称", trigger: "blur" }],
+      },
+    };
+  },
+  props: {
+    layerid: {
+      //自动注入的layerid
+      type: String,
+      default: "",
+    },
+    iframeData: {
+      //传递的数据
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+  },
+  methods: {
+    quxiao(reload) {
+      this.$layer.close(this.layerid);
+      //点击取消 不刷新列表   点击确认 保存成功刷新列表
+      if (reload) {
+        this.$parent.getInformation();
+      }
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.save();
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    async save() {
+      let { name, id } = this.form;
+      let data = { name, id };
+      let result = await this.$http({
+        method: "post",
+        data,
+        url: `/manage/goodsAge/save`,
+      });
+      if (result["code"] === 0) {
+        common.tip("success", "保存成功");
+        this.quxiao(true);
+      } else {
+        common.tip("error", "保存失败,请联系管理员");
+      }
+    },
+  },
+  watch: {
+    iframeData: {
+      handler: function () {
+        this.form = this.iframeData;
+      },
+      deep: true,
+      immediate: true,
+    },
+  },
+  created() {},
+};
+</script>
+
+<style lang="less" scoped>
+.Root {
+  padding: 50px;
+}
+.ivu-upload {
+  display: none;
+}
+</style>
+

+ 203 - 0
src/pages/collection/collectionYearList.vue

@@ -0,0 +1,203 @@
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <el-button type="primary" @click="edit({}, 'add')">新增</el-button>
+          </div>
+          <div class="info-right"></div>
+        </div>
+        <el-table
+          :data="tableData"
+          height="61vh"
+          class="collection-con"
+          :tree-props="{ children: 'children' }"
+          row-key="id"
+          style="width: 100%"
+        >
+          <el-table-column
+            type="index"
+            label="序号"
+            :index="indexMethod"
+          ></el-table-column>
+          <el-table-column prop="name" label="年代名称"></el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span
+                class="o-span"
+                v-if="$role == 'sys_admin'"
+                @click="edit(scope.row, 'edit')"
+                >编辑</span
+              >
+              <span
+                class="o-span"
+                v-if="
+                  ($role == 'sys_admin')
+                "
+                @click="del(scope.row)"
+                >删除</span
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="params.pageNum"
+            @size-change="handleSizeChange"
+            :page-size="params.pageSize"
+            :page-sizes="[10, 20, 50]"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+
+import MainTop from "@/components/main-top";
+import collectionYearEdit from "@/pages/collection/collectionYearEdit";
+
+const crumbData = [
+  {
+    name: "藏品年代",
+    id: 4 - 2,
+  },
+];
+
+export default {
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      crumbData,
+      tableData: [],
+      params: {
+        pageNum: 1,
+        pageSize: 10
+      },
+      total: 0
+    };
+  },
+  computed: {},
+  watch: {},
+  created() {
+    this.getInformation();
+  },
+  mounted() {},
+
+  methods: {
+    indexMethod(index) {
+      return (this.params.pageNum - 1) * this.params.pageSize + index + 1;
+    },
+    edit(item = {}, type) {
+      this.$layer.iframe({
+        content: {
+          content: collectionYearEdit,
+          parent: this,
+          data: { iframeData: item },
+        },
+        area: ["900px", "600px"],
+        title: `${type === "add" ? "新增" : "编辑"}藏品年代`,
+        maxmin: false,
+        shade: false,
+        shadeClose: false,
+        cancel: () => {
+          //关闭弹窗事件
+          this.getInformation()
+        },
+      });
+    },
+    del(item) {
+      this.$confirm("是否确认删除这个藏品年代?", "提示", {
+        confirmButtonText: "是",
+        cancelButtonText: "否",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http
+            .get(`/manage/goodsAge/remove/${item.id}`, {})
+            .then((res) => 
+            
+            {
+              if (res.code === 0) {
+                this.$alert("删除成功", "提示", {
+                  confirmButtonText: "确定",
+                  callback: () => {
+                    this.getInformation();
+                  },
+                });
+              } else {
+                this.$notify.error({
+                  title: "错误",
+                  message: res.msg,
+                });
+              }
+            });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    handleCurrentChange(val) {
+      this.params.pageNum = val;
+      this.getInformation();
+    },
+    handleSizeChange(val) {
+      this.params.pageSize = val;
+      this.getInformation();
+    },
+    async getInformation(reload = false) {
+      if (reload) {
+        this.params.pageNum = 1;
+        this.tableData = [];
+      }
+      let result = await this.$http({
+        method: "get",
+        url: "/manage/goodsAge/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.tableData = result.data;
+      this.total = result.data.length;
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow: auto;
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+</style>
+

+ 679 - 0
src/pages/content/Carousel.vue

@@ -0,0 +1,679 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con">
+        <div style="display:flex; align-items: center;">
+            <el-button style="margin-left:20px" type="primary" @click="show('', '')">上传党史军史</el-button>
+        </div>
+      </div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span>党史军史名称:</span>
+            <el-input class="elInput" v-model="inputKey" placeholder="请输入党史军史名称"></el-input>
+            <span style="margin-left:1.25rem;">新建时间:</span>
+            <el-date-picker
+              v-model="time"
+              type="daterange"
+              range-separator="-"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期">
+            </el-date-picker>
+            <el-button style="margin-left:1.25rem;" type="primary" @click="getInformation">查找</el-button>
+            <el-button @click="reset">重置</el-button>
+          </div>
+          <div class="info-right">
+          </div>
+        </div>
+        <el-table :data="tableData" height="61vh" class="collection-con" 
+        :tree-props="{children: 'children'}"
+        row-key="id"
+        style="width: 100%">
+          <el-table-column
+            v-for="(item, idx) in data"
+            :key="idx"
+            :sortable="item.prop==='viewCount'"
+            :prop="item.prop"
+            :label="item.label"
+          >
+            <template slot-scope="scope" >
+              <el-image 
+                 v-if="item.type === 'image'"
+                style="width:auto;height:125px;"
+                :src="scope.row[item.prop]">
+                <div slot="error" class="image-slot">
+                  <i class="el-icon-picture-outline"></i>
+                </div>
+              </el-image>
+              <span v-else v-html="scope.row[item.prop]||'-'"></span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope" >
+                <span class="o-span" v-if="($role=='sys_admin'||$role=='sys_high')" @click="show(scope.row,'edit')">编辑</span>
+                <span class="o-span" v-if="($role=='sys_admin'||$role=='sys_high')" @click="del(scope.row)">删除</span>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="currentPage"
+            @size-change="handleSizeChange"
+            :page-size="size"
+            :page-sizes="PAGESIZES"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+    <el-dialog :title="editTitle" :visible.sync="dialogFormVisible" width="50%">
+      <div class="add-con">
+        <div class="add-left">
+          <el-form :model="form" ref="knowledgeform">
+            <el-form-item
+              label="党史军史名称:"
+              :label-width="formLabelWidth"
+              prop="name"
+              :rules="{
+                required: true, message: '党史军史名称不能为空', trigger: 'blur'
+              }"
+            >
+              <el-input
+                v-model="form.name"
+                placeholder="请输入党史军史名称"
+                autocomplete="off"
+                :maxlength="25"
+                show-word-limit
+              ></el-input>
+            </el-form-item>
+
+            <el-form-item
+              label="知识链接:"
+              :label-width="formLabelWidth"
+              prop="knowledgeUrl"
+              :rules="{
+                required: true, message: '知识链接不能为空', trigger: 'blur'
+              }"
+            >
+              <el-input
+                v-model="form.knowledgeUrl"
+                placeholder="请输入https:// 链接"
+                autocomplete="off"
+              >
+            </el-input>
+             
+            </el-form-item>
+
+            <el-form-item :label="'链接图标:'"
+              prop="thumb"
+              :label-width="formLabelWidth"
+              :rules="{
+                required: true, message: `链接图标不能为空`, trigger: 'change'
+              }"
+             required>
+              <el-upload
+                class="upload-demo"
+                :action="uploadUrl"
+                :headers="{ token }"
+                :on-success="handleFileSuccess"
+                :on-error="handleError"
+                :before-upload="beforefileUpload"
+                :show-file-list="false"
+              >
+                <el-button size="small" type="primary">点击上传</el-button>
+              </el-upload>
+              <img v-if="form.thumb" style="max-width:300px;" :src="form.thumb" alt="">
+              <p style="color:#999;line-height:1;margin-top:20px">格式要求:</p>
+              <p style="color:#999;" v-for="(item,i) in desc[1]" :key="i"> 
+                {{item}}
+              </p>
+            </el-form-item>
+          </el-form>
+        </div>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="save">保 存</el-button>
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from "@/components/main-top";
+
+const crumbData = [
+  {
+    name: "党史军史管理",
+    id: 4,
+  },
+];
+
+
+let data = [
+  {
+    prop: "idx",
+    label: "序列"
+  },
+  {
+    prop: "name",
+    label: "党史军史名称"
+  },
+  {
+    prop: "knowledgeUrl",
+    label: "知识链接"
+  },
+ 
+  {
+    prop: "thumb",
+    label: "链接图标",
+    type:'image'
+  },
+  {
+    prop: "submitName",
+    label: "创建人"
+  },
+  {
+    prop: "createTime",
+    label: "创建时间"
+  }
+];
+
+let desc = {
+  1:['1、支持png和jpg的图片格式','2、最大可支持100M','3、建议分辨率:100*50']
+}
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      desc,
+      data,
+      crumbData,
+      time: "",
+      tableData: [],
+      inputKey: "",
+      currentPage: 1,
+      size: 25,
+      total: 0,
+      loading: false,
+      type: 1,
+      form: {
+        "id": "",
+        "knowledgeUrl": "",
+        "name": "",
+        "thumb": ""
+      },
+      dialogFormVisible: false,
+      showType:'',
+      formLabelWidth: "150px",
+      token: window.localStorage.getItem("token"),
+      uploadUrl: `${this.$serverName}manage/file/upload`,
+      uploadFlieUrl: `${this.$serverName}manage/fodder/uploadOriginal`
+    };
+  },
+  computed:{
+      editTitle(){
+        return this.showType ?'编辑党史军史':'新增党史军史'
+      },
+  },
+  watch: {
+    currentPage() {
+      this.refresh();
+    },
+    size() {
+      this.refresh();
+    },
+    type() {
+      this.refresh();
+    }
+  },
+  mounted() {
+    this.refresh()
+  },
+
+  methods: {
+    reset(){
+      this.inputKey=''
+      this.time=''
+    },
+  
+    handleError(){
+      this.$alert("上传失败,请稍后再试", "提示", {
+        confirmButtonText: "确定",
+        callback: () => {
+          this.loading.close()
+        },
+      });
+    },
+    handleFileSuccess(res) {
+      this.loading.close()
+      let { data } = res;
+      this.form.thumb = data.urlPath;
+    },
+    beforefileUpload(file){
+      let typeArr = ['.png','jpeg','jpg']
+      let type = this.isTypeBySend(file.name,typeArr);
+      if (!type) {
+        this.$message.error('只允许指定文件格式的文件');
+        return type
+      }
+      
+      let size = 100
+      const isLt = file.size / 1024 / 1024 < size;
+
+      if (!isLt) {
+        this.$message.error(`上传文件大小不能超过 ${size}MB!`);
+        return isLt;
+      }
+      this.loading = this.$loading(this.loadOption)
+    },
+    beforeAvatarUpload(file) {
+      let type = this.isImage(file.name);
+      if (!type) {
+        this.$message.error('只允许上传图片');
+        return type
+      }
+      const isLt2M = file.size / 1024 / 1024 < 20;
+
+      if (!isLt2M) {
+        this.$message.error("上传头像图片大小不能超过 20MB!");
+        return isLt2M;
+      }
+      this.loading = this.$loading(this.loadOption)
+    },
+
+    handleChange(item) {
+      console.log(item);
+    },
+
+
+    async getDetail(id) {
+      let result = await this.$http({
+        method: "get",
+        headers: {
+          token: window.localStorage.getItem("token"),
+        },
+        url: `/manage/knowledge/detail/${id}`,
+      });
+
+      this.form = result.data;
+    },
+  
+
+    show(item = "", type) {
+      this.dialogFormVisible = true;
+
+      this.showType = type;
+      this.form = {
+        id: "",
+        knowledgeUrl: "",
+        name: "",
+        thumb: ""
+      };
+
+      if (type === "edit") {
+        this.getDetail(item.id)
+      }
+    },
+    del(item) {
+      this.$confirm("删除后,信息将无法恢复,是否继续?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http
+            .get(`/manage/knowledge/remove/${item.id}`, {
+              headers: {
+                token: window.localStorage.getItem("token"),
+              },
+            })
+            .then((res) => {
+              if (res.code === 0) {
+                this.$alert("删除成功", "提示", {
+                  confirmButtonText: "确定",
+                  callback: () => {
+                    this.refresh();
+                  },
+                });
+              } else {
+                this.$notify.error({
+                  title: "错误",
+                  message: res.msg,
+                });
+              }
+            });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    async save() {
+      this.$refs["knowledgeform"].validate(async (valid) => {
+        if (valid) {
+          let {
+            id,
+            knowledgeUrl,
+            name,
+            thumb
+          } = this.form;
+          
+          knowledgeUrl = knowledgeUrl.substr(0,8).toLowerCase()=="https://"?knowledgeUrl:("https://"+knowledgeUrl);
+          let params = {
+            id,
+            knowledgeUrl,
+            name,
+            thumb
+          };
+          let result = await this.$http({
+            method: "post",
+            data: params,
+            headers: {
+              token: window.localStorage.getItem("token"),
+            },
+            url: `/manage/knowledge/save`,
+          });
+
+          if (result.code === 0) {
+            this.$alert("保存成功", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+                this.getInformation();
+              },
+            });
+          } else if (result.code === 60005) {
+            return
+          } else {
+            this.$notify.error({
+              title: "错误",
+              message: result.msg,
+            });
+          }
+        }
+      });
+    },
+
+    refresh() {
+      this.loading = true;
+      this.getInformation();
+      this.loading = false;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+    },
+    handleSizeChange(val) {
+      this.size = val;
+    },
+    async getInformation() {
+      this.dialogFormVisible = false;
+      let params = {
+        pageNum: this.currentPage,
+        pageSize: this.size,
+        searchKey: this.inputKey,
+        type: this.type,
+        startTime: this.time? (this.time[0].split(' ')[0] + ' 00:00:00') : '',
+        endTime: this.time? (this.time[1].split(' ')[0] + ' 23:59:59') : ''
+      };
+
+      let result = await this.$http({
+        method: "post",
+        data: params,
+        headers: {
+          token: window.localStorage.getItem("token"),
+        },
+        url: "/manage/knowledge/list",
+      });
+
+      if (result.code !== 0) {
+        return;
+      }
+      this.tableData = result.data.list;
+      this.total = result.data.total;
+      this.tableData.forEach((item, i) => {
+        item["idx"] = i + 1;
+      });
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.top-body .top-con {
+  font-weight: bold;
+}
+.table-title {
+  padding: 1rem 1rem 1rem 0;
+  font-size: 1rem;
+  color: #2d2d2d;
+  border-bottom: 0.0625rem solid #ccc;
+  display: flex;
+  justify-content: space-between;
+}
+
+.more {
+  color: #ec652d;
+  cursor: pointer;
+}
+
+.top-right {
+  background-color: #ec652d;
+  height: 3.5625rem;
+  line-height: 3.5625rem;
+  color: #fff;
+  padding: 0 1.875rem;
+  border-radius: 0.3125rem;
+  font-size: 1.125rem;
+  font-weight: bold;
+}
+
+.search-body {
+  background-color: #fff;
+  margin: 1.25rem 0;
+}
+
+.interface-table {
+  height: calc(100% - 17.1875rem);
+  overflow-x: hidden;
+  background-color: #fff;
+  padding: 0 1.125rem 2.375rem;
+  box-sizing: border-box;
+}
+
+.zan-con {
+  display: flex;
+  width: 100%;
+  justify-content: space-around;
+  margin-top: 1.5rem;
+  text-align: center;
+  font-size: 1.125rem;
+}
+
+.zan-con .line {
+  height: 8rem;
+  width: 0.0625rem;
+  background: #ccc;
+}
+
+.zan-con .zan-contain {
+  display: flex;
+  justify-content: space-between;
+  flex-direction: column;
+}
+
+.zan-con .zan-contain p {
+  font-size: 2.25rem;
+}
+
+.zan-con .zan-contain p:first-child {
+  font-size: 0.875rem;
+  line-height: 1.5;
+}
+
+.zan-sub {
+  text-align: right;
+  margin-top: 1.25rem;
+  color: #a5a5a5;
+  font-size: 0.875rem;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+
+.o-span {
+  cursor: pointer;
+  color: rgb(7, 152, 244);
+}
+
+.collection-con {
+  width: 100%;
+  overflow-x: hidden;
+  overflow-y: auto;
+  height: 60vh;
+}
+
+.collection-con ul {
+  display: flex;
+  flex-wrap: wrap;
+  margin-top: 1.25rem;
+}
+
+.collection-con ul li {
+  width: 24%;
+  margin-right: 1%;
+  cursor: pointer;
+  font-size: 0.8rem;
+  color: #2d2d2d;
+  margin-bottom: 1.25rem;
+}
+
+.collection-con ul .li-img {
+  position: relative;
+  height: 250px;
+  font-size: 0;
+}
+
+.collection-con ul .elchbox{
+  position: absolute;
+  left: 10px;
+  top: 5px;
+}
+
+
+
+
+
+.collection-con ul .li-img div span {
+  margin-right: 0.625rem;
+}
+
+.collection-con ul img {
+  width: 100%;
+}
+
+.collection-con {
+  li {
+    position: relative;
+    .li-txt {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      background: #dedede;
+      font-size: 16px;
+      line-height: 2;
+    }
+    .oper {
+      position: absolute;
+      top: 10px;
+      right: 10px;
+      display: none;
+      > img {
+        width: 40px;
+        height: 40px;
+        background: #b63c25;
+        margin-left: 20px;
+        border-radius: 4px;
+        padding: 5px;
+      }
+    }
+    &:hover {
+      .oper {
+        display: block;
+      }
+    }
+  }
+}
+
+.add-con {
+  display: flex;
+  justify-content: space-between;
+}
+
+.add-left {
+  flex: 1;
+}
+
+.add-right {
+  flex: 1;
+  margin-left: 10%;
+}
+</style>
+
+<style>
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  /* height: 178px; */
+  display: block;
+}
+</style>

+ 569 - 0
src/pages/content/Collection.vue

@@ -0,0 +1,569 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con">
+        <el-button type="primary" @click="$router.push({name:'edit-collection',query:{type},params:{type:0,id:'none'}})">新增精品典藏</el-button>
+      </div>
+    </main-top>
+    <div class="table-interface">
+      <div class="con-left">
+        <el-menu :default-active="`1-${type}`" @select="handleSelect" class="el-menu-vertical-demo" :collapse="isCollapse">
+          <el-submenu index="1">
+            <template slot="title">
+              <i class="el-icon-menu"></i>
+              <span slot="title">精品典藏</span>
+            </template>
+            <el-menu-item v-for="(item,i) in collectionType" :key="i" :index="'1-'+item.id">{{item.name}}</el-menu-item>
+          </el-submenu>
+        </el-menu>
+        <div class="sousuo" @click="isCollapse=!isCollapse">
+          <i :class="isCollapse?'el-icon-arrow-right':'el-icon-arrow-left'"></i>
+        </div>
+      </div>
+      <div class="top-body">
+        <ul class="tab">
+          <li @click="status = 5" :class="{active:status !== 4}">待审核</li>
+          <li @click="status = 4" :class="{active:status === 4}">审核通过</li>
+        </ul>
+        <div class="info-top">
+          <div class="info-left">
+            <span>发布时间:</span>
+            <el-date-picker
+              v-model="time"
+              type="daterange"
+              range-separator="-"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期">
+            </el-date-picker>
+            <span style="margin-left:1.25rem;">状态:</span>
+            <el-select style="width:6.25rem;" v-model="status" placeholder="请选择">
+              <el-option label="全部" :value="5"></el-option>
+              <el-option v-for="(item,i) in statusArr" :key="i" :label="item.name" :value="item.id"></el-option>
+            </el-select>
+            <span style="margin-left:1.25rem;">标题关键字:</span>
+            <el-input class="elInput" v-model="inputKey" placeholder="请输入标题关键字搜索"></el-input>
+            <el-button type="primary" @click="getInformation">查找</el-button>
+            <el-button @click="reset">重置</el-button>
+          </div>
+          <div class="info-right">
+          </div>
+        </div>
+        <el-table :data="tableData" height="55vh" class="collection-con" style="width: 100%">
+          <el-table-column
+            v-for="(item, idx) in data"
+            :key="idx"
+            :sortable="item.prop==='viewCount'"
+            :prop="item.prop"
+            :width="item.prop === 'thumb'?250:'auto'"
+            :label="item.label"
+          >
+            <template slot-scope="scope" >
+              <el-switch
+                v-model="scope.row[item.prop]"
+                v-if="item.prop === 'display'"
+                v-show="status === 4"
+                :disabled="!($role=='sys_admin'||$role=='sys_high')"
+                @change="changeState(scope.row)"
+                inactive-color="#ccc">
+              </el-switch>
+              <el-image 
+                v-else-if="item.prop === 'thumb'"
+                style="width:auto;height:125px;"
+                :src="scope.row[item.prop]"
+                :preview-src-list="[scope.row[item.prop]]">
+                <div slot="error" class="image-slot">
+                  <i class="el-icon-picture-outline"></i>
+                </div>
+              </el-image>
+              <el-input type="number" class="icenter" v-else-if="(item.prop === 'sort')&&($role=='sys_admin'||$role=='sys_high')" @blur="handleSort(scope.row)" v-model="scope.row[item.prop]"></el-input>
+              <span v-else v-html="scope.row[item.prop]||'-'"></span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope" >
+              <template v-if="status !== 4">
+                <template v-if="scope.row.statusStr === '待审核'">
+                  <span class="o-span" @click="goto(scope.row)" v-if="scope.row.statusStr === '待审核'">
+                    {{($role=='sys_admin'||$role=='sys_high') ? '审核':'查看'}}
+                  </span>
+                </template>
+                <template v-else>
+                  <span class="o-span" @click="goto(scope.row)">编辑</span>
+                  <span class="o-span" @click="del(scope.row)">删除</span>
+                </template>
+              </template>
+              <template v-else>
+                <span class="o-span" @click="goto(scope.row)">查看</span>
+                <span class="o-span" v-if="(!scope.row.display)&&($role=='sys_admin'||$role=='sys_high')" @click="del(scope.row)">删除</span>
+              </template>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="currentPage"
+            @size-change="handleSizeChange"
+            :page-size="size"
+            :page-sizes="PAGESIZES"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+import {changeState} from '@/util/commonfn.js'
+const crumbData = [
+  {
+    name: '精品典藏管理',
+    id: 4
+  }
+]
+
+let collectionType = [
+  {
+    id:3,
+    name:'实物模型'
+  },
+  {
+    id:1,
+    name:'专题图库'
+  },
+  {
+    id:2,
+    name:'视频档案'
+  }
+]
+
+
+
+let data = [
+  {
+    prop: "idx",
+    label: "编号"
+  },
+  {
+    prop: "title",
+    label: "标题"
+  },
+  {
+    prop: "thumb",
+    label: "封面图片"
+  },
+  {
+    prop: "sort",
+    label: "排序"
+  },
+  {
+    prop: "viewCount",
+    label: "阅读"
+  },
+  {
+    prop: "submitName",
+    label: "发布人"
+  },
+  {
+    prop: "createTime",
+    label: "发布时间"
+  },
+  {
+    prop: "statusStr",
+    label: "所属状态"
+  }
+];
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+  },
+  data () {
+    return {
+      isCollapse:false,
+      crumbData,
+      time:'',
+      tableData: [],
+      inputKey: '',
+      currentPage: 1,
+      size: 25,
+      total: 0,
+      collectionType,
+      loading: false,
+      status:5,
+      type:this.$route.params.type
+    }
+  },
+  computed:{
+    data(){
+      data.pop()
+      let item = this.status === 4?{
+        prop: "display",
+        label: "是否显示"
+      }:{
+        prop: "statusStr",
+        label: "所属状态"
+      }
+      data.push(item)
+      return data
+    }
+  },
+  watch: {
+    currentPage () {
+      this.refresh()
+    },
+    size () {
+      this.refresh()
+    },
+    status () {
+      this.refresh()
+    },
+    type(){
+      this.refresh()
+    }
+  },
+  mounted () {
+    this.refresh()
+  },
+ 
+  methods: {
+    handleSort(item=""){
+      if(!item||!item.sort)return
+      this.$http.get(`/manage/goods/sort/${item.id}/${item.sort}`, {
+        headers: {
+          token: window.localStorage.getItem("token"),
+        },
+      })
+      .then((res) => {
+        if (res.code === 0) {
+          // this.refresh();
+        } else {
+          this.$notify.error({
+            title: "错误",
+            message: res.msg
+          });
+        }
+      });
+    },
+    changeState(item) {
+      changeState(item,'goods',()=>{
+          this.refresh();
+      })
+    },
+    handleSelect(index){
+      this.type = Number(index.substr(-1))
+      this.$router.push({
+        name:'collection',
+        params:{
+          type:this.type
+        }
+      })
+      // this.refresh()
+    },
+    reset(){
+      this.inputKey=''
+      this.status=5
+    },
+    del (item) {
+      let ids = item.id
+      this.$confirm('删除后,信息将无法恢复,是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http.get(`/manage/goods/remove/${ids}`,{headers: {
+          token: window.localStorage.getItem('token')
+        }}).then(res => {
+          if (res.code === 0) {
+            this.$alert('删除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: () => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.msg
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    
+    gotoShow (item) {
+      this.$router.push({ name: 'show-collection', params: { id: item.id } })
+    },
+
+    goto (item) {
+      this.$router.push({ name: 'edit-collection', params: { type: 1,id:item.id } })
+    },
+ 
+    refresh () {
+      this.loading = true
+      this.getInformation()
+      this.loading = false
+    },
+    handleCurrentChange (val) {
+      this.currentPage = val
+    },
+    handleSizeChange(val){
+      this.size = val
+    },
+    async getInformation () {
+      let params = {
+        pageNum:this.currentPage,
+        pageSize: this.size,
+        searchKey: this.inputKey,
+        startTime: this.time? (this.time[0].split(' ')[0] + ' 00:00:00') : '',
+        endTime: this.time? (this.time[1].split(' ')[0] + ' 23:59:59') : '',
+        status: this.status,
+        type:this.type
+      }
+
+      let result = await this.$http({
+        method: 'post',
+        data: params,
+        headers: {
+          token: window.localStorage.getItem('token')
+        },
+        url: '/manage/goods/list'
+      })
+
+      if (result.code !== 0) {
+        return
+      }
+      this.tableData = result.data.list
+      this.total = result.data.total
+      this.tableData.forEach((item, i) => {
+        item["idx"] = i + 1;
+        item["typeStr"] = this.typeStr[item.type];
+        item["statusStr"] = this.statusStr[item.status];
+        item["createTime"] = item["createTime"].split(' ')[0] + '<br/>' +item["createTime"].split(' ')[1]
+        item["display"] = Boolean(item["display"]);
+      });
+    }
+  }
+}
+</script>
+
+
+<style lang="less" scoped>
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+  width: 90%;
+}
+
+.top-body .top-con{
+  font-weight: bold;
+}
+.table-title{
+  padding: 1rem 1rem 1rem 0 ;
+  font-size: 1rem;
+  color: #2d2d2d;
+  border-bottom: .0625rem solid #ccc;
+  display: flex;
+  justify-content: space-between;
+}
+
+.more{
+  color: #ec652d;
+  cursor: pointer;
+}
+
+.top-right{
+  background-color: #ec652d;
+  height: 3.5625rem;
+  line-height: 3.5625rem;
+  color: #fff;
+  padding: 0 1.875rem;
+  border-radius: .3125rem;
+  font-size: 1.125rem;
+  font-weight: bold;
+}
+
+.search-body{
+  background-color: #fff;
+  margin: 1.25rem 0;
+}
+
+.interface-table{
+  height: calc(100% - 17.1875rem);
+  overflow-x: hidden;
+  background-color: #fff;
+  padding: 0 1.125rem 2.375rem;
+  box-sizing: border-box;
+}
+
+.zan-con{
+  display: flex;
+  width: 100%;
+  justify-content: space-around;
+  margin-top: 1.5rem;
+  text-align: center;
+  font-size: 1.125rem;
+}
+
+.zan-con .line{
+  height: 8rem;
+  width: .0625rem;
+  background: #ccc;
+}
+
+.zan-con .zan-contain{
+  display: flex;
+  justify-content: space-between;
+  flex-direction: column;
+}
+
+.zan-con .zan-contain p{
+  font-size: 2.25rem;
+}
+
+.zan-con .zan-contain p:first-child{
+  font-size: .875rem;
+  line-height: 1.5;
+}
+
+.zan-sub{
+  text-align: right;
+  margin-top: 1.25rem;
+  color: #a5a5a5;
+  font-size: .875rem;
+}
+
+.table-interface{
+  height: calc(100% - 3rem);
+  display: flex;
+  justify-content: space-between;
+  background-color: #fff;
+  .con-left{
+    border-right: solid 1px #e5e5e5;
+    position: relative;
+    margin-right: 30px;
+    .sousuo{
+      position: absolute;
+      top: 50%;
+      transform: translateY(-50%);
+      right: -30px;
+      cursor: pointer;
+    }
+  }
+}
+
+
+.info-top{
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: .0625rem #a5a5a5 solid;
+}
+
+.o-span{
+  cursor: pointer;
+  color: rgb(7, 152, 244);
+}
+
+.collection-con{
+  width: 100%;
+  overflow-x: hidden;
+  overflow-y: auto;
+  height: 55vh;
+}
+
+
+
+.collection-con ul{
+  display: flex;
+  flex-wrap: wrap;
+  margin-top: 1.25rem;
+}
+
+.collection-con ul li {
+  width: 24%;
+  margin-right: 1%;
+  cursor: pointer;
+  font-size: .8rem;
+  color: #2d2d2d;
+  margin-bottom: 1.25rem;
+}
+
+.collection-con ul .li-img {
+  position: relative;
+  
+}
+.collection-con ul .li-img div{
+  position: absolute;
+  left: .625rem;
+  bottom: .625rem;
+  color: #fff;
+}
+
+.collection-con ul .li-img div span{
+  margin-right: .625rem;
+}
+
+
+.collection-con ul img {
+  width: 100%;
+}
+
+.collection-con{
+  .li-txt,.li-name{
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+  .li-name{
+    margin-top: .5rem;
+    div{
+      font-size: 1rem;
+      font-weight: bold;
+      color: #532F1C;
+      &:last-of-type{
+        color: #707070;
+        font-size: .875rem;
+        font-weight: normal;
+        span{
+          margin-left: .30rem;
+          &:last-of-type{
+            &:hover{
+              color: #409EFF;
+            }
+          }
+          &:hover{
+            color: #c56351;
+          }
+        }
+      }
+    }
+  }
+}
+
+.el-menu-vertical-demo:not(.el-menu--collapse) {
+  width: 200px;
+  min-height: 400px;
+}
+.el-menu{
+  border-right: none!important;
+}
+</style>

+ 424 - 0
src/pages/content/Comment.vue

@@ -0,0 +1,424 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span>发布时间:</span>
+            <el-date-picker
+              v-model="time"
+              type="daterange"
+              range-separator="-"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期">
+            </el-date-picker>
+            <span style="margin-left:1.25rem;">评论内容关键字:</span>
+            <el-input class="elInput" v-model="inputKey" placeholder="请输入评论内容关键字搜索"></el-input>
+            <el-button type="primary" @click="getInformation">查找</el-button>
+            <el-button @click="reset">重置</el-button>
+          </div>
+          <div class="info-right">
+          </div>
+        </div>
+        <el-table :data="tableData" height="61vh" class="collection-con" 
+        :tree-props="{children: 'children'}"
+        row-key="id"
+        style="width: 100%">
+          <el-table-column
+            v-for="(item, idx) in data"
+            :key="idx"
+            :sortable="item.prop==='viewCount'"
+            :prop="item.prop"
+            :label="item.label"
+          >
+            <template slot-scope="scope" >
+              <el-switch
+                v-model="scope.row[item.prop]"
+                v-if="item.prop === 'display'"
+                @change="changeState(scope.row)"
+                :disabled="!($role=='sys_admin'||$role=='sys_high')"
+                inactive-color="#ccc">
+              </el-switch>
+              <span v-else v-html="scope.row[item.prop]||'-'"></span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope" >
+              <template></template>
+              <span v-if="scope.row.qiyong === '注销'">已注销</span>
+              <template v-else>
+                <span class="o-span" v-if="($role=='sys_admin'||$role=='sys_high')" @click="del(scope.row)">删除</span>
+              </template>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="currentPage"
+            @size-change="handleSizeChange"
+            :page-size="size"
+            :page-sizes="PAGESIZES"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+import {changeState} from '@/util/commonfn.js'
+const crumbData = [
+  {
+    name: '留言管理',
+    id: 4
+  }
+]
+
+let spiritType = [
+  {
+    id:'news',
+    name:'新闻'
+  },
+  {
+    id:'notice',
+    name:'公告'
+  }
+]
+
+
+let data = [
+      {
+        prop: "idx",
+        label: "编号"
+      },
+      {
+        prop: "nickName",
+        label: "用户昵称"
+      },
+      {
+        prop: "msg",
+        label: "评论内容"
+      },
+      {
+        prop: "updateTime",
+        label: "发布时间"
+      },
+      {
+        prop: "display",
+        label: "是否显示"
+      }
+    ];
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+  },
+  data () {
+    return {
+      data,
+      crumbData,
+      time:'',
+      tableData: [],
+      inputKey: '',
+      currentPage: 1,
+      size: 25,
+      total: 0,
+      loading: false,
+      spiritType
+    }
+  },
+  watch: {
+    currentPage () {
+      this.refresh()
+    },
+    size () {
+      this.refresh()
+    }
+  },
+  mounted () {
+    this.refresh()
+  },
+ 
+  methods: {
+    changeState(item) {
+      changeState(item,'comment',()=>{
+          this.refresh();
+      })
+    },
+    reset(){
+      this.inputKey=''
+      this.time = ''
+    },
+    del (item) {
+      let ids = item.id
+      this.$confirm('删除后,信息将无法恢复,是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http.get(`/manage/comment/removes/${ids}`,{headers: {
+          token: window.localStorage.getItem('token')
+        }}).then(res => {
+          if (res.code === 0) {
+            this.$alert('删除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: () => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.msg
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+
+    refresh () {
+      this.loading = true
+      this.getInformation()
+      this.loading = false
+    },
+    handleCurrentChange (val) {
+      this.currentPage = val
+    },
+    handleSizeChange(val){
+      this.size = val
+    },
+    async getInformation () {
+      let params = {
+          pageNum:this.currentPage,
+          pageSize: this.size,
+          searchKey: this.inputKey,
+          startTime: this.time? (this.time[0].split(' ')[0] + ' 00:00:00') : '',
+          endTime: this.time? (this.time[1].split(' ')[0] + ' 23:59:59') : ''
+      }
+
+      let result = await this.$http({
+        method: 'post',
+        data: params,
+        headers: {
+          token: window.localStorage.getItem('token')
+        },
+        url: '/manage/comment/list'
+      })
+
+      if (result.code !== 0) {
+        return
+      }
+      this.tableData = result.data.list
+      this.total = result.data.total
+      this.tableData.forEach((item, i) => {
+        item["idx"] = i + 1;
+        item["typeStr"] = this.typeStr[item.type];
+        item["display"] = Boolean(item["display"]);
+        item.children&&item.children.forEach((sub)=>{
+          sub["display"] = Boolean(sub["display"]);
+        })
+      });
+    }
+  }
+}
+</script>
+
+
+<style lang="less" scoped>
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.top-body .top-con{
+  font-weight: bold;
+}
+.table-title{
+  padding: 1rem 1rem 1rem 0 ;
+  font-size: 1rem;
+  color: #2d2d2d;
+  border-bottom: .0625rem solid #ccc;
+  display: flex;
+  justify-content: space-between;
+}
+
+.more{
+  color: #ec652d;
+  cursor: pointer;
+}
+
+.top-right{
+  background-color: #ec652d;
+  height: 3.5625rem;
+  line-height: 3.5625rem;
+  color: #fff;
+  padding: 0 1.875rem;
+  border-radius: .3125rem;
+  font-size: 1.125rem;
+  font-weight: bold;
+}
+
+.search-body{
+  background-color: #fff;
+  margin: 1.25rem 0;
+}
+
+.interface-table{
+  height: calc(100% - 17.1875rem);
+  overflow-x: hidden;
+  background-color: #fff;
+  padding: 0 1.125rem 2.375rem;
+  box-sizing: border-box;
+}
+
+.zan-con{
+  display: flex;
+  width: 100%;
+  justify-content: space-around;
+  margin-top: 1.5rem;
+  text-align: center;
+  font-size: 1.125rem;
+}
+
+.zan-con .line{
+  height: 8rem;
+  width: .0625rem;
+  background: #ccc;
+}
+
+.zan-con .zan-contain{
+  display: flex;
+  justify-content: space-between;
+  flex-direction: column;
+}
+
+.zan-con .zan-contain p{
+  font-size: 2.25rem;
+}
+
+.zan-con .zan-contain p:first-child{
+  font-size: .875rem;
+  line-height: 1.5;
+}
+
+.zan-sub{
+  text-align: right;
+  margin-top: 1.25rem;
+  color: #a5a5a5;
+  font-size: .875rem;
+}
+
+.table-interface{
+  height: calc(100% - 3rem);
+}
+
+
+.info-top{
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: .0625rem #a5a5a5 solid;
+}
+
+.o-span{
+  cursor: pointer;
+  color: rgb(7, 152, 244);
+}
+
+.collection-con{
+  width: 100%;
+  overflow-x: hidden;
+  overflow-y: auto;
+  height: 61vh;
+}
+
+
+
+.collection-con ul{
+  display: flex;
+  flex-wrap: wrap;
+  margin-top: 1.25rem;
+}
+
+.collection-con ul li {
+  width: 24%;
+  margin-right: 1%;
+  cursor: pointer;
+  font-size: .8rem;
+  color: #2d2d2d;
+  margin-bottom: 1.25rem;
+}
+
+.collection-con ul .li-img {
+  position: relative;
+  
+}
+.collection-con ul .li-img div{
+  position: absolute;
+  left: .625rem;
+  bottom: .625rem;
+  color: #fff;
+}
+
+.collection-con ul .li-img div span{
+  margin-right: .625rem;
+}
+
+
+.collection-con ul img {
+  width: 100%;
+}
+
+.collection-con{
+  .li-txt,.li-name{
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+  .li-name{
+    margin-top: .5rem;
+    div{
+      font-size: 1rem;
+      font-weight: bold;
+      color: #532F1C;
+      &:last-of-type{
+        color: #707070;
+        font-size: .875rem;
+        font-weight: normal;
+        span{
+          margin-left: .30rem;
+          &:last-of-type{
+            &:hover{
+              color: #409EFF;
+            }
+          }
+          &:hover{
+            color: #c56351;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 742 - 0
src/pages/content/Dynamic.vue

@@ -0,0 +1,742 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData"></main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span style="margin-left:1.25rem;">标题关键字:</span>
+            <el-input class="elInput paddingmore" :maxlength="50"
+                show-word-limit v-model="inputKey" placeholder="请输入场景名称"></el-input>
+            <el-button type="primary" @click="getInformation">查询</el-button>
+          </div>
+          <div class="info-right"></div>
+        </div>
+        <el-table :data="tableData" height="55vh" class="collection-con" style="width: 100%">
+          <el-table-column
+            v-for="(item, idx) in data"
+            :key="idx"
+            :prop="item.prop"
+            :label="item.label"
+            :width="item.prop === 'thumb'?400:'auto'"
+          >
+            <template slot-scope="scope">
+              <img
+                v-if="item.prop === 'thumb'"
+                :src="scope.row[item.prop]"
+                style="width:auto;height:128px;"
+                alt
+              />
+              <span v-else>{{scope.row[item.prop]||'-'}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <template v-if="status === 4 || status === 6">
+                <template>
+                  <span class="o-span" @click="goto(scope.row)">查看</span>
+                  <span class="o-span" @click="gotoEdit(scope.row)">编辑</span>
+                  <span class="o-span" v-if="scope.row.sceneCode != '699' && scope.row.sceneCode != '698'" @click="del(scope.row)">删除</span>
+                  <span class="o-span" style="color:#ccc;cursor:auto;" v-else>删除</span>
+                </template>
+              </template>
+              <template v-else>
+                <span class="o-span" @click="show(scope.row, 'edit')">编辑</span>
+                <span class="o-span" @click="del(scope.row)">删除</span>
+              </template>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="currentPage"
+            @size-change="handleSizeChange"
+            :page-size="size"
+            :page-sizes="PAGESIZES"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+    <el-dialog :title="editTitle" :visible.sync="dialogFormVisible" width="40%">
+      <div class="add-con">
+        <div class="add-left">
+          <el-form :model="form">
+            <el-form-item
+              label="视频名称:"
+              prop="title"
+              :label-width="formLabelWidth"
+              :rules="{
+                required: true, message: '视频名称不能为空', trigger: 'blur'
+              }"
+            >
+              <el-input
+                v-model="form.title"
+                placeholder="请输入视频名称"
+                autocomplete="off"
+                :maxlength="15"
+                show-word-limit
+              ></el-input>
+            </el-form-item>
+
+            <el-form-item label="封面图片:">
+              <el-upload
+                class="avatar-uploader"
+                :action="uploadUrl"
+                :headers="{
+                  token,
+                }"
+                :show-file-list="false"
+                :on-success="handleThumbSuccess"
+                :on-error="handleError"
+                :before-upload="beforeAvatarUpload"
+              >
+                <img v-if="form.thumb" :src="form.thumb" class="avatar" />
+                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              </el-upload>
+              <p style="color:#999;margin-left:60px;line-height:1">1、支持png、jpg、gif和jpeg的图片格式</p>
+              <p style="color:#999;margin-left:60px;">2、用于列表展示</p>
+            </el-form-item>
+
+            <el-form-item label="视频文件:">
+              <el-upload
+                class="upload-demo"
+                :action="uploadUrl"
+                :headers="{ token }"
+                :on-success="handleFileSuccess"
+                :on-error="handleError"
+                :before-upload="beforefileUpload"
+                :show-file-list="false"
+              >
+                <el-button size="small" type="primary">点击上传</el-button>
+              </el-upload>
+              <p v-if="form.fileName" style="color:#999;margin-left:80px;">{{form.fileName}}</p>
+              <p style="color:#999;margin-left:60px;">1、支持视频文件,最大为1.5GB大小</p>
+            </el-form-item>
+          </el-form>
+        </div>
+        <div class="add-right">
+          <el-form ref="videoform" :model="form">
+            <el-form-item label="素材描述:" prop="nickName" :label-width="formLabelWidth">
+              <el-input
+                v-model="form.description"
+                placeholder="请输入素材描述"
+                type="textarea"
+                autocomplete="off"
+                :autosize="{ minRows: 4}"
+                :maxlength="500"
+                show-word-limit
+              ></el-input>
+            </el-form-item>
+          </el-form>
+        </div>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="save()">保 存</el-button>
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from "@/components/main-top";
+const crumbData = [
+  {
+    name: "场景管理",
+    id: 4,
+  },
+];
+
+let spiritType = [
+  {
+    id: "news",
+    name: "新闻",
+  },
+  {
+    id: "notice",
+    name: "公告",
+  },
+];
+
+let data = [
+  {
+    prop: "idx",
+    label: "编号",
+  },
+  {
+    prop: "sceneCode",
+    label: "场景",
+  },
+  {
+    prop: "sceneTitle",
+    label: "名称",
+  },
+  {
+    prop: "submitName",
+    label: "发布人",
+  },
+  {
+    prop: "createTime",
+    label: "发布时间",
+  }
+];
+
+let videodata = [
+  {
+    prop: "idx",
+    label: "编号",
+  },
+  {
+    prop: "title",
+    label: "视频名称",
+  },
+
+  {
+    prop: "thumb",
+    label: "封面图片",
+  },
+
+  {
+    prop: "video",
+    label: "视频文件",
+  },
+
+  {
+    prop: "submitName",
+    label: "发布人",
+  },
+  {
+    prop: "createTime",
+    label: "发布时间",
+  },
+  {
+    prop: "display",
+    label: "是否显示",
+  },
+];
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      crumbData,
+      time: "",
+      tableData: [],
+      inputKey: "",
+      currentPage: 1,
+      size: 25,
+      total: 0,
+      loading: false,
+      status: 4,
+      spiritType,
+      fetchurl: "/manage/scene/list",
+      type: 1,
+      form: {
+        description: "",
+        id: "",
+        img: "",
+        status: "",
+        thumb: "",
+        title: "",
+        video: "",
+        fileId: "",
+        fileName: "",
+      },
+      dialogFormVisible: false,
+      showType: "",
+      formLabelWidth: "120px",
+      file: "",
+      token: window.localStorage.getItem("token"),
+      uploadUrl: `${this.$serverName}manage/file/upload`,
+    };
+  },
+  computed: {
+    data() {
+      let tmp = this.status === 5 ? videodata : data;
+      return tmp;
+    },
+    editTitle() {
+      return this.showType ? "编辑视频" : "新增视频";
+    },
+  },
+  watch: {
+    currentPage() {
+      this.refresh();
+    },
+    size() {
+      this.refresh();
+    }
+  },
+  mounted() {
+    this.refresh();
+  },
+
+  methods: {
+    handleThumbSuccess(res) {
+      let { data } = res;
+      this.form.thumb = data.urlPath;
+      this.form.img = data.urlPath;
+    },
+    handleError() {
+      this.$alert("上传失败,请稍后再试", "提示", {
+        confirmButtonText: "确定",
+        callback: () => {
+          this.loading.close();
+        },
+      });
+    },
+    handleFileSuccess(res) {
+      let { data } = res;
+      this.form.fileName = data.fileName;
+      this.form.fileId = data.id;
+      this.form.video = data.urlPath;
+    },
+    beforefileUpload(file) {
+      let typeArr = ["avi", "mov", "rmvb", "rm", "flv", "mp4", "3gp"];
+      let type = this.isTypeBySend(file.name, typeArr);
+      if (!type) {
+        this.$message.error("只允许指定文件格式的文件");
+        return type;
+      }
+
+      let size = 1500;
+      const isLt = file.size / 1024 / 1024 < size;
+
+      if (!isLt) {
+        this.$message.error(`上传文件大小不能超过 ${size}MB!`);
+      }
+      return isLt;
+    },
+    beforeAvatarUpload(file) {
+      const isLt2M = file.size / 1024 / 1024 < 20;
+      if (!isLt2M) {
+        this.$message.error("上传头像图片大小不能超过 20MB!");
+      }
+      return isLt2M;
+    },
+    show(item = "", type) {
+      this.dialogFormVisible = true;
+      (this.file = ""), (this.showType = type);
+      this.form = {
+        description: "",
+        id: "",
+        img: "",
+        status: "",
+        thumb: "",
+        title: "",
+        video: "",
+        fileId: "",
+        fileName: "",
+      };
+
+      if (type === "edit") {
+        this.getDetail(item.id);
+      }
+    },
+    async getDetail(id) {
+      let result = await this.$http({
+        method: "get",
+        headers: {
+          token: window.localStorage.getItem("token"),
+        },
+        url: `/manage/video/detail/${id}`,
+      });
+
+      this.form = result.data;
+    },
+    changeState(item) {
+      let url = "";
+      if (this.status === 5) {
+        url = `/manage/video/display/${item.id}`;
+      } else {
+        url =
+          this.status === 4
+            ? `/manage/scene/display/${item.id}/out`
+            : `/manage/scene/display/${item.id}/in`;
+      }
+
+      this.$http
+        .get(url, {
+          headers: {
+            token: window.localStorage.getItem("token"),
+          },
+        })
+        .then((res) => {
+          if (res.code === 0) {
+            this.refresh();
+          } else {
+            this.$notify.error({
+              title: "错误",
+              message: res.msg,
+            });
+          }
+        });
+    },
+
+    goto(item) {
+      window.open(`/SuperTwo${item.sceneCode.split('_')[0]}/index.html?m=${item.sceneCode}`, "_blank");
+    },
+
+    gotoEdit(item) {
+      window.open(`/edit-backstage/edit_zh.html?m=${item.sceneCode}`, "_blank");
+    },
+
+    del(item) {
+      let url = this.status === 5 ? "video" : "scene";
+      let ids = item.id;
+      this.$confirm("删除后,信息将无法恢复,是否继续?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http
+            .get(`/manage/${url}/removes/${ids}`, {
+              headers: {
+                token: window.localStorage.getItem("token"),
+              },
+            })
+            .then((res) => {
+              if (res.code === 0) {
+                this.$alert("删除成功", "提示", {
+                  confirmButtonText: "确定",
+                  callback: () => {
+                    this.refresh();
+                  },
+                });
+              } else {
+                this.$notify.error({
+                  title: "错误",
+                  message: res.msg,
+                });
+              }
+            });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+
+    refresh() {
+      this.loading = true;
+      this.getInformation();
+      this.loading = false;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+    },
+    handleSizeChange(val) {
+      this.size = val;
+    },
+    async save() {
+      this.$refs["videoform"].validate(async (valid) => {
+        if (valid) {
+          let {
+            description,
+            id = "",
+            img,
+            status,
+            thumb,
+            title,
+            video,
+            fileId,
+            fileName,
+          } = this.form;
+
+          let params = {
+            id,
+            description,
+            fileId,
+            fileName,
+            img,
+            status,
+            thumb,
+            title,
+            video,
+          };
+          let result = await this.$http({
+            method: "post",
+            data: params,
+            headers: {
+              token: window.localStorage.getItem("token"),
+            },
+            url: `/manage/video/save`,
+          });
+
+          if (result.code === 0) {
+            this.$alert("保存成功", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+                this.getInformation();
+              },
+            });
+          } else {
+            this.$notify.error({
+              title: "错误",
+              message: result.msg,
+            });
+          }
+        }
+      });
+    },
+    async getInformation() {
+      this.dialogFormVisible = false;
+      let params = {
+        pageNum: this.currentPage,
+        pageSize: this.size,
+        searchKey: this.inputKey,
+      };
+
+      let result = await this.$http({
+        method: "post",
+        data: params,
+        headers: {
+          token: window.localStorage.getItem("token"),
+        },
+        url: this.fetchurl,
+      });
+
+      if (result.code !== 0) {
+        return;
+      }
+      this.tableData = result.data.list;
+      this.total = result.data.total;
+      this.tableData.forEach((item, i) => {
+        item["idx"] = i + 1;
+        item["display"] = Boolean(item["display"]);
+      });
+    },
+  },
+};
+</script>
+
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.top-body .top-con {
+  font-weight: bold;
+}
+.table-title {
+  padding: 1rem 1rem 1rem 0;
+  font-size: 1rem;
+  color: #2d2d2d;
+  border-bottom: 0.0625rem solid #ccc;
+  display: flex;
+  justify-content: space-between;
+}
+
+.more {
+  color: #ec652d;
+  cursor: pointer;
+}
+
+.top-right {
+  background-color: #ec652d;
+  height: 3.5625rem;
+  line-height: 3.5625rem;
+  color: #fff;
+  padding: 0 1.875rem;
+  border-radius: 0.3125rem;
+  font-size: 1.125rem;
+  font-weight: bold;
+}
+
+.search-body {
+  background-color: #fff;
+  margin: 1.25rem 0;
+}
+
+.interface-table {
+  height: calc(100% - 17.1875rem);
+  overflow-x: hidden;
+  background-color: #fff;
+  padding: 0 1.125rem 2.375rem;
+  box-sizing: border-box;
+}
+
+.zan-con {
+  display: flex;
+  width: 100%;
+  justify-content: space-around;
+  margin-top: 1.5rem;
+  text-align: center;
+  font-size: 1.125rem;
+}
+
+.zan-con .line {
+  height: 8rem;
+  width: 0.0625rem;
+  background: #ccc;
+}
+
+.zan-con .zan-contain {
+  display: flex;
+  justify-content: space-between;
+  flex-direction: column;
+}
+
+.zan-con .zan-contain p {
+  font-size: 2.25rem;
+}
+
+.zan-con .zan-contain p:first-child {
+  font-size: 0.875rem;
+  line-height: 1.5;
+}
+
+.zan-sub {
+  text-align: right;
+  margin-top: 1.25rem;
+  color: #a5a5a5;
+  font-size: 0.875rem;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+
+.o-span {
+  cursor: pointer;
+  color: rgb(7, 152, 244);
+}
+
+.collection-con {
+  width: 100%;
+  overflow-x: hidden;
+  overflow-y: auto;
+  height: 55vh;
+}
+
+.collection-con ul {
+  display: flex;
+  flex-wrap: wrap;
+  margin-top: 1.25rem;
+}
+
+.collection-con ul li {
+  width: 24%;
+  margin-right: 1%;
+  cursor: pointer;
+  font-size: 0.8rem;
+  color: #2d2d2d;
+  margin-bottom: 1.25rem;
+}
+
+.collection-con ul .li-img {
+  position: relative;
+}
+.collection-con ul .li-img div {
+  position: absolute;
+  left: 0.625rem;
+  bottom: 0.625rem;
+  color: #fff;
+}
+
+.collection-con ul .li-img div span {
+  margin-right: 0.625rem;
+}
+
+.collection-con ul img {
+  width: 100%;
+}
+
+.collection-con {
+  .li-txt,
+  .li-name {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+  .li-name {
+    margin-top: 0.5rem;
+    div {
+      font-size: 1rem;
+      font-weight: bold;
+      color: #532f1c;
+      &:last-of-type {
+        color: #707070;
+        font-size: 0.875rem;
+        font-weight: normal;
+        span {
+          margin-left: 0.3rem;
+          &:last-of-type {
+            &:hover {
+              color: #409eff;
+            }
+          }
+          &:hover {
+            color: #c56351;
+          }
+        }
+      }
+    }
+  }
+}
+.add-con {
+  display: flex;
+  justify-content: space-between;
+}
+
+.add-left {
+  flex: 1;
+}
+
+.add-right {
+  flex: 1;
+  margin-left: 10%;
+}
+</style>
+<style>
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  /* height: 178px; */
+  display: block;
+}
+</style>

+ 857 - 0
src/pages/content/Spirit.vue

@@ -0,0 +1,857 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con">
+        <div style="display:flex; align-items: center;">
+            <el-button style="margin-left:20px" type="primary" @click="show('', '')">上传文物</el-button>
+        </div>
+      </div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span>文物名称:</span>
+            <el-input class="elInput" v-model="inputKey" placeholder="请输入文物名称"></el-input>
+            <span style="margin-left:1.25rem;">新建时间:</span>
+            <el-date-picker
+              v-model="time"
+              type="daterange"
+              range-separator="-"
+              value-format="yyyy-MM-dd hh:mm:ss"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期">
+            </el-date-picker>
+            <el-button style="margin-left:1.25rem;" type="primary" @click="getInformation">查找</el-button>
+            <el-button @click="reset">重置</el-button>
+          </div>
+          <div class="info-right">
+          </div>
+        </div>
+        <el-table :data="tableData" height="61vh" class="collection-con" 
+        :tree-props="{children: 'children'}"
+        row-key="id"
+        style="width: 100%">
+          <el-table-column
+            v-for="(item, idx) in data"
+            :key="idx"
+            :sortable="item.prop==='viewCount'"
+            :prop="item.prop"
+            :label="item.label"
+          >
+            <template slot-scope="scope" >
+              <el-switch
+                v-model="scope.row[item.prop]"
+                v-if="item.prop === 'display'"
+                @change="changeState(scope.row)"
+                :disabled="!($role=='sys_admin'||$role=='sys_high')"
+                inactive-color="#ccc">
+              </el-switch>
+              <el-image 
+                 v-else-if="item.type === 'image'"
+                style="width:auto;height:125px;"
+                :src="scope.row[item.prop]">
+                <div slot="error" class="image-slot">
+                  <i class="el-icon-picture-outline"></i>
+                </div>
+              </el-image>
+              <span v-else v-html="scope.row[item.prop]||'-'"></span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope" >
+                <span class="o-span" v-if="($role=='sys_admin'||$role=='sys_high')" @click="show(scope.row,'edit')">编辑</span>
+                <span class="o-span" v-if="($role=='sys_admin'||$role=='sys_high')" @click="del(scope.row)">删除</span>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="currentPage"
+            @size-change="handleSizeChange"
+            :page-size="size"
+            :page-sizes="PAGESIZES"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+    <el-dialog :title="editTitle" :visible.sync="dialogFormVisible" width="60%">
+      <div class="add-con" v-if="dialogFormVisible && changeType">
+        <div class="add-left">
+          <el-form :model="form" ref="fodderform">
+            <el-form-item label="上传类型:" :rules="{
+              required:true
+            }" :label-width="formLabelWidth">
+              <el-radio-group :disabled="showType==='edit'" v-model="form.type">
+                <el-radio :label="1">图片</el-radio>
+                <el-radio :label="2">视频</el-radio>
+                <el-radio :label="3">模型</el-radio>
+              </el-radio-group>
+            </el-form-item>
+
+            <el-form-item
+              label="文物名称:"
+              :label-width="formLabelWidth"
+              prop="name"
+              :rules="{
+                required: true, message: '文物名称不能为空', trigger: 'blur'
+              }"
+            >
+              <el-input
+                v-model="form.name"
+                placeholder="请输入文物名称"
+                autocomplete="off"
+                maxlength="50"
+                class="paddingmore"
+                show-word-limit
+              ></el-input>
+            </el-form-item>
+
+            <el-form-item
+              label="所属类别:"
+              :label-width="formLabelWidth"
+              prop="category"
+              :rules="{
+                required: true, message: '所属类别不能为空', trigger: 'change'
+              }"
+            >
+                
+              <el-select
+                style="width:100%;"
+                v-model="form.category"
+                placeholder="请选择所属类别"
+              >
+                <el-option
+                  v-for="(item, i) in typeli"
+                  :key="i"
+                  :label="item.name"
+                  :value="item.id"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+
+            <el-form-item :label="'文物文件:'"
+              prop="fileUrl"
+              :label-width="formLabelWidth"
+              :rules="{
+                required: true, message: `文物文件不能为空`, trigger: 'change'
+              }"
+             required>
+              <el-upload
+                class="upload-demo"
+                :action="uploadFlieUrl"
+                :headers="{ token }"
+                :on-success="handleFileSuccess"
+                :on-error="handleError"
+                :before-upload="beforefileUpload"
+                :show-file-list="false"
+              >
+                <el-button size="small" type="primary">点击上传</el-button>
+              </el-upload>
+              <el-input v-model="form.fileUrl" v-show="false"></el-input>
+
+              <p v-if="form.type==1">
+                <img style="max-width:200px;" :src="form.fileUrl" alt="">
+              </p>
+              <p v-else-if="form.type == 2">
+                <video style="max-width:200px;" v-if="form.fileUrl" :src="form.fileUrl" autoplay controls></video>
+              </p>
+              <template v-else>
+                <p v-if="form.fileUrl" style="color:#999;">链接地址:<a target="_blank" :href="`/model-page/Model.html?m=${getLastName(form.fileUrl)}`">{{`/model-page/Model.html?m=${getLastName(form.fileUrl)}`}}</a></p>
+              </template>
+
+              <p style="color:#999;line-height:1;margin-top:20px">格式要求:</p>
+              <p style="color:#999;" v-for="(item,i) in desc[form.type]" :key="i"> 
+                {{item}}
+              </p>
+            </el-form-item>
+          </el-form>
+        </div>
+        <div class="add-right">
+          <el-form>
+            <el-form-item label="文物缩略图:"
+              prop="thumb"
+              :rules="{
+                required: true, message: '文物缩略图不能为空', trigger: 'change'
+              }"
+            >
+           
+              <el-upload
+                class="avatar-uploader"
+                :action="uploadUrl"
+                :headers="{
+                  token
+                }"
+                :show-file-list="false"
+                :on-error="handleError"
+                :on-success="handleThumbSuccess"
+                :before-upload="beforeAvatarUpload"
+              >
+                <img v-if="form.thumb" :src="form.thumb" class="avatar" />
+                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              </el-upload>
+              <p style="color:#999;margin-left:60px;">格式要求:</p>
+              <p style="color:#999;margin-left:60px;line-height:1">
+                1、支持png、jpg、gif和jpeg的图片格式
+              </p>
+              <p style="color:#999;margin-left:60px;">2、用于列表展示</p>
+            </el-form-item>
+
+            <el-form-item
+              label="文物描述:"
+              prop="description"
+            >
+              <el-input
+                v-model="form.description"
+                placeholder="请输入文物描述"
+                type="textarea"
+                autocomplete="off"
+                :autosize="{ minRows: 4}"
+                :maxlength="200" 
+                show-word-limit
+              ></el-input>
+            </el-form-item>
+          </el-form>
+           
+        </div>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="save">保 存</el-button>
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from "@/components/main-top";
+import {changeState} from '@/util/commonfn.js'
+
+const crumbData = [
+  {
+    name: "文物管理",
+    id: 4,
+  },
+];
+
+let rawType = [
+'胜利回归,奉命组建',
+'神圣进驻,不辱使命',
+'强军兴军,定海神针',
+'风雨同舟 守望相助——协助澳门救助台风“天鸽"灾害',
+'功勋荣誉'
+]
+
+let typeli = rawType.map((item,i)=>{
+  return {
+    name:item,
+    id:String(i+1)
+  }
+})
+
+
+let data = [
+  {
+    prop: "idx",
+    label: "序列"
+  },
+  {
+    prop: "name",
+    label: "文物名称"
+  },
+  {
+    prop: "categoryStr",
+    label: "所属类别"
+  },
+  {
+    prop: "typeStr",
+    label: "上传类型"
+  },
+  
+  {
+    prop: "thumb",
+    label: "文物缩略图",
+    type:'image'
+  },
+  {
+    prop: "createTime",
+    label: "新建时间"
+  },
+  {
+    prop: "display",
+    label: "是否显示"
+  }
+];
+
+let desc = {
+  1:['1、支持png、jpg、gif和jpeg的图片格式','2、最大支持10M'],
+  2:['1、支持.mp4,.avi,.rmvb和.mov格式','2、最大支持300M'],
+  3:['1、支持.4dage格式','2、最大为300M大小。']
+}
+
+let typeStrs = {
+  1:'图片',
+  2:'视频',
+  3:'模型'
+}
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      desc,
+      data,
+      fileList:[],
+      duoci:0,
+      crumbData,
+      time: "",
+      tableData: [],
+      inputKey: "",
+      currentPage: 1,
+      size: 25,
+      total: 0,
+      loading: false,
+      type: 1,
+      form: {
+        "category": "",
+        "description": "",
+        "fileId": "",
+        "id": "",
+        "name": "",
+        "thumb": "",
+        "type": 1
+      },
+      changeType:true,
+      dialogFormVisible: false,
+      showType:'',
+      formLabelWidth: "120px",
+      token: window.localStorage.getItem("token"),
+      uploadUrl: `${this.$serverName}manage/file/upload`,
+      uploadFlieUrl: `${this.$serverName}manage/fodder/uploadOriginal`,
+      typeli
+    };
+  },
+  computed:{
+      editTitle(){
+        return this.showType ?'编辑文物':'新增文物'
+      },
+  },
+  watch: {
+    currentPage() {
+      this.refresh();
+    },
+    size() {
+      this.refresh();
+    },
+    type() {
+      this.refresh();
+    },
+    'form.type':function () {
+        if (this.showType != 'edit') {
+          this.changeType = false
+          this.form.fileUrl = ''
+          this.form.fileName = ''
+          this.form.fileId = ''
+          setTimeout(() => {
+            this.changeType = true 
+          });
+        }
+    }
+  },
+  mounted() {
+    this.refresh()
+  },
+
+  methods: {
+    getLastName(data){
+      return data.substring(data.lastIndexOf("/")+1)
+    },
+    changeState(item) {
+      changeState(item,'fodder',()=>{
+          this.refresh();
+      })
+    },
+    reset(){
+      this.inputKey=''
+      this.time=''
+    },
+    handleThumbSuccess(res) {
+      this.loading.close()
+      let { data } = res;
+      this.form.thumb = data.urlPath;
+    },
+    handleError(){
+      this.$alert("上传失败,请稍后再试", "提示", {
+        confirmButtonText: "确定",
+        callback: () => {
+          this.loading.close()
+        },
+      });
+    },
+    handleFileSuccess(res) {
+      this.loading.close()
+      let { data } = res;
+      this.form.fileUrl = data.urlPath;
+      this.form.fileName = data.fileName;
+      this.form.fileId = data.id;
+    },
+    beforefileUpload(file){
+      let typeArr = this.form.type === 1 ? ['.png','jpeg','gif','jpg'] : (this.form.type === 2? ['avi','mov','rmvb','rm','flv','mp4','3gp']:['4dage'])
+      let type = this.isTypeBySend(file.name,typeArr);
+      if (!type) {
+        this.$message.error('只允许指定文件格式的文件');
+        return type
+      }
+      
+      let size = this.form.type === 1 ? 10 : 300
+      const isLt = file.size / 1024 / 1024 < size;
+
+      if (!isLt) {
+        this.$message.error(`上传文件大小不能超过 ${size}MB!`);
+        return isLt;
+      }
+      this.loading = this.$loading(this.loadOption)
+    },
+    beforeAvatarUpload(file) {
+      let type = this.isImage(file.name);
+      if (!type) {
+        this.$message.error('只允许上传图片');
+        return type
+      }
+      const isLt2M = file.size / 1024 / 1024 < 20;
+
+      if (!isLt2M) {
+        this.$message.error("上传头像图片大小不能超过 20MB!");
+        return isLt2M;
+      }
+      this.loading = this.$loading(this.loadOption)
+    },
+
+    handleChange(item) {
+      console.log(item);
+    },
+
+
+    async getDetail(id) {
+      let result = await this.$http({
+        method: "get",
+        headers: {
+          token: window.localStorage.getItem("token"),
+        },
+        url: `/manage/fodder/detail/${id}`,
+      });
+
+      this.form = result.data;
+      console.log(this.form);
+    },
+    checkAll(val){
+      let arr = []
+      this.tableData.forEach(item=>{
+        item.check = val
+        arr.push(item)
+      })
+      this.tableData = arr
+    },
+    handleCheck(item,i){
+      this.$set(this.tableData,i,item)
+    },
+    show(item = "", type) {
+      this.dialogFormVisible = true;
+
+      this.showType = type;
+      this.form = {
+        id: "",
+        description: "",
+        name: "",
+        thumb: "",
+        type: this.type,
+        fileUrl:'',
+        fileName:'',
+        fileId:''
+      };
+
+      if (type === "edit") {
+        this.getDetail(item.id)
+      }
+    },
+    del(item) {
+      this.$confirm("删除后,信息将无法恢复,是否继续?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http
+            .get(`/manage/fodder/removes/${item.id}`, {
+              headers: {
+                token: window.localStorage.getItem("token"),
+              },
+            })
+            .then((res) => {
+              if (res.code === 0) {
+                this.$alert("删除成功", "提示", {
+                  confirmButtonText: "确定",
+                  callback: () => {
+                    this.refresh();
+                  },
+                });
+              } else {
+                this.$notify.error({
+                  title: "错误",
+                  message: res.msg,
+                });
+              }
+            });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    async save() {
+      this.$refs["fodderform"].validate(async (valid) => {
+        if (valid) {
+          let {
+            id,
+            name,
+            thumb,
+            fileId,
+            type,
+            fileUrl,
+            category,
+            description
+          } = this.form;
+          if (!thumb) {
+            return this.$alert("文物缩略图不能为空", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+              },
+            });
+          }
+          
+          let params = {
+            id,
+            fileUrl,
+            fileId,
+            name,
+            category,
+            thumb,
+            type,
+            description
+          };
+          let result = await this.$http({
+            method: "post",
+            data: params,
+            headers: {
+              token: window.localStorage.getItem("token"),
+            },
+            url: `/manage/fodder/save`,
+          });
+
+          if (result.code === 0) {
+            this.$alert("保存成功", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+                this.getInformation();
+              },
+            });
+          } else if (result.code === 60005) {
+            return
+          } else {
+            this.$notify.error({
+              title: "错误",
+              message: result.msg,
+            });
+          }
+        }
+      });
+    },
+
+    refresh() {
+      this.loading = true;
+      this.getInformation();
+      this.loading = false;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+    },
+    handleSizeChange(val) {
+      this.size = val;
+    },
+    async getInformation() {
+      this.dialogFormVisible = false;
+      let params = {
+        pageNum: this.currentPage,
+        pageSize: this.size,
+        searchKey: this.inputKey,
+        startTime: this.time? (this.time[0].split(' ')[0] + ' 00:00:00') : '',
+        endTime: this.time? (this.time[1].split(' ')[0] + ' 23:59:59') : ''
+      };
+
+      let result = await this.$http({
+        method: "post",
+        data: params,
+        headers: {
+          token: window.localStorage.getItem("token"),
+        },
+        url: "/manage/fodder/list",
+      });
+
+      if (result.code !== 0) {
+        return;
+      }
+      this.tableData = result.data.list;
+      this.total = result.data.total;
+      this.tableData.forEach((item, i) => {
+        item["idx"] = i + 1;
+        item["typeStr"] = typeStrs[item.type];
+        let category = typeli.filter(i=>i.id==item.category).length>0 && (typeli.filter(i=>i.id==item.category))[0].name
+        item["categoryStr"] = category
+        item["display"] = Boolean(item["display"]);
+      });
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.top-body .top-con {
+  font-weight: bold;
+}
+.table-title {
+  padding: 1rem 1rem 1rem 0;
+  font-size: 1rem;
+  color: #2d2d2d;
+  border-bottom: 0.0625rem solid #ccc;
+  display: flex;
+  justify-content: space-between;
+}
+
+.more {
+  color: #ec652d;
+  cursor: pointer;
+}
+
+.top-right {
+  background-color: #ec652d;
+  height: 3.5625rem;
+  line-height: 3.5625rem;
+  color: #fff;
+  padding: 0 1.875rem;
+  border-radius: 0.3125rem;
+  font-size: 1.125rem;
+  font-weight: bold;
+}
+
+.search-body {
+  background-color: #fff;
+  margin: 1.25rem 0;
+}
+
+.interface-table {
+  height: calc(100% - 17.1875rem);
+  overflow-x: hidden;
+  background-color: #fff;
+  padding: 0 1.125rem 2.375rem;
+  box-sizing: border-box;
+}
+
+.zan-con {
+  display: flex;
+  width: 100%;
+  justify-content: space-around;
+  margin-top: 1.5rem;
+  text-align: center;
+  font-size: 1.125rem;
+}
+
+.zan-con .line {
+  height: 8rem;
+  width: 0.0625rem;
+  background: #ccc;
+}
+
+.zan-con .zan-contain {
+  display: flex;
+  justify-content: space-between;
+  flex-direction: column;
+}
+
+.zan-con .zan-contain p {
+  font-size: 2.25rem;
+}
+
+.zan-con .zan-contain p:first-child {
+  font-size: 0.875rem;
+  line-height: 1.5;
+}
+
+.zan-sub {
+  text-align: right;
+  margin-top: 1.25rem;
+  color: #a5a5a5;
+  font-size: 0.875rem;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+
+.o-span {
+  cursor: pointer;
+  color: rgb(7, 152, 244);
+}
+
+.collection-con {
+  width: 100%;
+  overflow-x: hidden;
+  overflow-y: auto;
+  height: 60vh;
+}
+
+.collection-con ul {
+  display: flex;
+  flex-wrap: wrap;
+  margin-top: 1.25rem;
+}
+
+.collection-con ul li {
+  width: 24%;
+  margin-right: 1%;
+  cursor: pointer;
+  font-size: 0.8rem;
+  color: #2d2d2d;
+  margin-bottom: 1.25rem;
+}
+
+.collection-con ul .li-img {
+  position: relative;
+  height: 250px;
+  font-size: 0;
+}
+
+.collection-con ul .elchbox{
+  position: absolute;
+  left: 10px;
+  top: 5px;
+}
+
+
+
+
+
+.collection-con ul .li-img div span {
+  margin-right: 0.625rem;
+}
+
+.collection-con ul img {
+  width: 100%;
+}
+
+.collection-con {
+  li {
+    position: relative;
+    .li-txt {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      background: #dedede;
+      font-size: 16px;
+      line-height: 2;
+    }
+    .oper {
+      position: absolute;
+      top: 10px;
+      right: 10px;
+      display: none;
+      > img {
+        width: 40px;
+        height: 40px;
+        background: #b63c25;
+        margin-left: 20px;
+        border-radius: 4px;
+        padding: 5px;
+      }
+    }
+    &:hover {
+      .oper {
+        display: block;
+      }
+    }
+  }
+}
+
+.add-con {
+  display: flex;
+  justify-content: space-between;
+}
+
+.add-left {
+  flex: 1;
+}
+
+.add-right {
+  flex: 1;
+  margin-left: 10%;
+}
+
+
+</style>
+
+<style>
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  /* height: 178px; */
+  display: block;
+}
+
+.el-textarea__inner{
+  padding-right: 60px!important;
+}
+</style>

+ 762 - 0
src/pages/content/sceneAudio.vue

@@ -0,0 +1,762 @@
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con">
+        <div style="display: flex; align-items: center">
+          <el-button
+            style="margin-left: 20px"
+            type="primary"
+            @click="show({}, 'add')"
+            >新增语音</el-button
+          >
+        </div>
+      </div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span>音频名称:</span>
+            <el-input
+              class="elInput"
+              v-model="inputKey"
+              placeholder="请输入音频名称"
+            ></el-input>
+            <span style="margin-left: 1.25rem">新建时间:</span>
+            <el-date-picker
+              v-model="time"
+              type="daterange"
+              range-separator="-"
+              value-format="yyyy-MM-dd hh:mm:ss"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+            >
+            </el-date-picker>
+            <el-button
+              style="margin-left: 1.25rem"
+              type="primary"
+              @click="getInformation"
+              >查询</el-button
+            >
+            <el-button @click="reset">重置</el-button>
+          </div>
+          <div class="info-right"></div>
+        </div>
+        <el-table
+          :data="tableData"
+          height="61vh"
+          class="collection-con"
+          :tree-props="{ children: 'children' }"
+          row-key="id"
+          style="width: 100%"
+        >
+          <el-table-column type="index" label="序号"></el-table-column>
+          <el-table-column prop="name" label="音频名称"></el-table-column>
+          <el-table-column label="所属展区">
+            <template slot-scope="scope">
+              <span>{{ exhibitionAreaType[scope.row.type] }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="音频图标">
+            <template slot-scope="scope">
+              <!-- 加个data才能访问 -->
+              <img :src="'/data/' + scope.row.icon" />
+            </template>
+          </el-table-column>
+          <el-table-column width="300" label="音频二维码">
+            <template slot-scope="scope">
+              <!-- 加个data才能访问 -->
+              <img :src="'/data/' + scope.row.qrCode" />
+            </template>
+          </el-table-column>
+          <el-table-column prop="createTime" label="新建时间"></el-table-column>
+
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span
+                class="o-span"
+                v-if="$role == 'sys_admin' || $role == 'sys_high'"
+                @click="show(scope.row, 'edit')"
+                >编辑</span
+              >
+              <span
+                class="o-span"
+                v-if="scope.row.isIndex != '1' && ($role == 'sys_admin' || $role == 'sys_high')"
+                @click="del(scope.row)"
+                >删除</span
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="currentPage"
+            @size-change="handleSizeChange"
+            :page-size="size"
+            :page-sizes="PAGESIZES"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+    <!-- 弹框 -->
+    <el-dialog :title="editTitle" :visible.sync="dialogFormVisible" width="60%">
+      <div class="add-con" v-if="dialogFormVisible && changeType">
+        <div class="add-left">
+          <el-form :model="form" ref="fodderform">
+            <el-form-item
+              label="音频名称:"
+              :label-width="formLabelWidth"
+              prop="name"
+              :rules="{
+                required: true,
+                message: '音频名称不能为空',
+                trigger: 'blur',
+              }"
+            >
+              <el-input
+                v-model="form.name"
+                placeholder="请输入音频名称"
+                autocomplete="off"
+                maxlength="50"
+                class="paddingmore"
+                show-word-limit
+              ></el-input>
+            </el-form-item>
+
+            <el-form-item
+              label="所属展区:"
+              :label-width="formLabelWidth"
+              :rules="{
+                required: true,
+                message: '所属展区不能为空',
+                trigger: 'change',
+              }"
+            >
+              <el-select
+                style="width: 100%"
+                v-model="form.type"
+                placeholder="请选择所属展区"
+              >
+                <el-option
+                  v-for="(item, i) in typeli"
+                  :key="i"
+                  :label="item.label"
+                  :value="item.value"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+
+            <el-form-item label="音频图标:" :label-width="formLabelWidth">
+              <el-upload
+                class="avatar-uploader"
+                ref="upload"
+                accept=".jpg,.png"
+                :headers="{ token }"
+                :action="uploadUrl"
+                :on-error="handleError"
+                :show-file-list="false"
+                :on-success="handleIconSuccess"
+                :before-upload="beforeIconUpload"
+                :on-change="handleChange"
+                :on-remove="handleRemove"
+              >
+                <img
+                  v-if="form.icon"
+                  :src="'/data/' + form.icon"
+                  class="avatar"
+                />
+                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              </el-upload>
+              <div>
+                <p style="color: #999">格式要求:</p>
+                <p style="color: #999; line-height: 1">
+                  1、支持png,jpeg的图片格式
+                </p>
+                <p style="color: #999">2、最大可支持50M</p>
+                <p style="color: #999">3、建议分辨率:50*50</p>
+              </div>
+            </el-form-item>
+            <el-form-item :label="'音频文件:'" :label-width="formLabelWidth">
+              <el-upload
+                :file-list="audioFileList"
+                class="upload-demo"
+                accept=".mp3,.wav,.flac,.m4a"
+                :action="uploadFlieUrl"
+                :headers="{ token }"
+                :on-success="handleFileSuccess"
+                :on-error="handleError"
+                :before-upload="beforefileUpload"
+                :on-change="handleAudioFilesChange"
+                :on-remove="handleAudioFilesRemove"
+              >
+                <el-button size="small" type="primary">点击上传</el-button>
+              </el-upload>
+              <p v-if="form.audio" style="color: #999">
+                <a target="_blank" :href="'/data/' + form.audio">{{ form.fileName }}</a>
+              </p>
+              <div>
+                <p style="color: #999">格式要求:</p>
+                <p style="color: #999; line-height: 1">
+                  1、支持WAV,FLAC,MP3音频文件格式
+                </p>
+                <p style="color: #999">2、最大可支持500M</p>
+              </div>
+            </el-form-item>
+
+            <el-form-item
+              v-if="form.qrCode"
+              label="音频二维码:"
+              :label-width="formLabelWidth"
+            >
+              <img :src="'/data/' + form.qrCode" class="avatar" />
+            </el-form-item>
+          </el-form>
+        </div>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="save">保 存</el-button>
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from "@/components/main-top";
+import { changeState } from "@/util/commonfn.js";
+const exhibitionAreaType = {
+  1: "主厅",
+  2: "附厅",
+  3: "序厅",
+};
+
+const crumbData = [
+  {
+    name: "场景音频管理",
+    id: 12,
+  },
+];
+
+let typeli = [
+  { label: "主厅", value: 1 },
+  { label: "附厅", value: 2 },
+  { label: "序厅", value: 3 },
+];
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      fileList: [],
+      audioFileList: [],
+      duoci: 0,
+      crumbData,
+      time: "",
+      tableData: [],
+      inputKey: "",
+      currentPage: 1,
+      size: 25,
+      total: 0,
+      loading: false,
+      form: {
+        id: "",
+        name: "",
+        type: 2,
+        icon: "",
+        audio: "",
+        fileName:""
+      },
+      changeType: true,
+      dialogFormVisible: false,
+      showType: "",
+      formLabelWidth: "120px",
+      token: window.localStorage.getItem("token"),
+      uploadUrl: `${this.$serverName}manage/sceneAudio/material/upload/img`,
+      uploadFlieUrl: `${this.$serverName}manage/sceneAudio/material/upload/audio`,
+      typeli,
+      exhibitionAreaType,
+    };
+  },
+  computed: {
+    editTitle() {
+      return this.showType === "edit" ? "编辑场景音频" : "新增场景音频";
+    },
+  },
+  watch: {
+    currentPage() {
+      this.refresh();
+    },
+    size() {
+      this.refresh();
+    },
+    type() {
+      this.refresh();
+    },
+    "form.type": function () {
+      if (this.showType != "edit") {
+        this.changeType = false;
+        this.form.fileUrl = "";
+        this.form.fileName = "";
+        this.form.fileId = "";
+        setTimeout(() => {
+          this.changeType = true;
+        });
+      }
+    },
+  },
+  mounted() {
+    this.refresh();
+  },
+
+  methods: {
+    handleChange(file) {
+      this.fileList = this.fileList.length === 0 ? this.fileList : [];
+      this.fileList.push(file["raw"]);
+    },
+    handleRemove(file) {
+      let index = this.fileList.findIndex((item) => {
+        return item.uid === file.uid;
+      });
+      this.fileList.splice(index, 1);
+    },
+    handleAudioFilesRemove() {
+      this.audioFileList = [];
+      this.form.audio = "";
+      this.form.fileName = "";
+    },
+    handleAudioFilesChange(file) {
+      this.audioFileList = [];
+      this.audioFileList.push(file);
+      this.form.audio = file.response && file.response.data && file.response.data.path;
+      this.form.fileName = file.response && file.response.data && file.response.data.fileName;
+    },
+    changeState(item) {
+      changeState(item, "fodder", () => {
+        this.refresh();
+      });
+    },
+    reset() {
+      this.inputKey = "";
+      this.time = "";
+    },
+    handleIconSuccess(res) {
+      this.loading.close();
+      let { data } = res;
+      this.form.icon = data.path;
+    },
+    handleError() {
+      this.$alert("上传失败,请稍后再试", "提示", {
+        confirmButtonText: "确定",
+        callback: () => {
+          this.loading.close();
+        },
+      });
+    },
+    handleFileSuccess(res) {
+      this.loading.close();
+      let { data } = res;
+      this.form.audio = data.path;
+    },
+    beforefileUpload(file) {
+      // console.log('file',file)
+      // let typeArr = ["mp4"]
+      // console.log('this',this)
+      // let type = this.isTypeBySend(file.name, typeArr);
+      // if (!type) {
+      //   this.$message.error("只允许指定文件格式的文件");
+      //   return type;
+      // }
+
+      let size = 500;
+      const isLt = file.size / 1024 / 1024 < size;
+
+      if (!isLt) {
+        this.$message.error(`上传文件大小不能超过 ${size}MB!`);
+        return isLt;
+      }
+      this.loading = this.$loading(this.loadOption);
+    },
+    beforeIconUpload(file) {
+      // let type = this.isImage(file.name);
+      // if (!type) {
+      //   this.$message.error("只允许上传图片");
+      //   return type;
+      // }
+      let size = 50;
+      const isLt = file.size / 1024 / 1024 < size;
+
+      if (!isLt) {
+        this.$message.error(`上传头像图片大小不能超过 ${size}MB!`);
+        return isLt;
+      }
+      this.loading = this.$loading(this.loadOption);
+    },
+    show(item = {}, type) {
+      console.log("item", item);
+      this.dialogFormVisible = true;
+      this.showType = type;
+      this.form = { id: "", name: "", icon: "", audio: "",fileName:'' };
+      if (type === "add") {
+        console.log("add");
+        this.audioFileList = [];
+      }
+      if (type === "edit") {
+        this.form = { ...item };
+        let file = { name: item.fileName, url: `/${this.form.audio}` };
+        this.audioFileList = [file];
+      }
+    },
+    del(item) {
+      this.$confirm("删除后,信息将无法恢复,是否继续?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http
+            .get(`/manage/sceneAudio/remove/${item.id}`, {})
+            .then((res) => {
+              if (res.code === 0) {
+                this.$alert("删除成功", "提示", {
+                  confirmButtonText: "确定",
+                  callback: () => {
+                    this.getInformation();
+                  },
+                });
+              } else {
+                this.$notify.error({
+                  title: "错误",
+                  message: res.msg,
+                });
+              }
+            });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    tipError(msg) {
+      this.$notify.error({
+        title: "错误",
+        message: msg,
+      });
+    },
+    async save() {
+      this.$refs["fodderform"].validate(async (valid) => {
+        if (valid) {
+          let { id, name, type, icon, audio,fileName } = this.form;
+          let data = {
+            id,
+            name,
+            type,
+            icon,
+            audio,
+            fileName
+          };
+          if (!data.icon) {
+            this.tipError("音频图标不能为空");
+            return;
+          }
+          if (!data.audio) {
+            this.tipError("音频不能为空");
+            return;
+          }
+          let result = await this.$http({
+            method: "post",
+            data,
+            url: `/manage/sceneAudio/save`,
+          });
+          if (result.code === 0) {
+            this.$alert("保存成功", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+                this.getInformation();
+              },
+            });
+          } else if (result.code === 60005) {
+            return;
+          } else {
+            this.$notify.error({
+              title: "错误",
+              message: result.msg,
+            });
+          }
+        }
+      });
+    },
+
+    refresh() {
+      this.loading = true;
+      this.getInformation();
+      this.loading = false;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+    },
+    handleSizeChange(val) {
+      this.size = val;
+    },
+    async getInformation() {
+      this.dialogFormVisible = false;
+      let params = {
+        pageNum: this.currentPage,
+        pageSize: this.size,
+        searchKey: this.inputKey,
+        startTime: this.time ? this.time[0].split(" ")[0] + " 00:00:00" : "",
+        endTime: this.time ? this.time[1].split(" ")[0] + " 23:59:59" : "",
+      };
+
+      let result = await this.$http({
+        method: "post",
+        data: params,
+        headers: {
+          token: window.localStorage.getItem("token"),
+        },
+        url: "/manage/sceneAudio/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.tableData = result.data.list;
+      this.total = result.data.total;
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.top-body .top-con {
+  font-weight: bold;
+}
+.table-title {
+  padding: 1rem 1rem 1rem 0;
+  font-size: 1rem;
+  color: #2d2d2d;
+  border-bottom: 0.0625rem solid #ccc;
+  display: flex;
+  justify-content: space-between;
+}
+
+.more {
+  color: #ec652d;
+  cursor: pointer;
+}
+
+.top-right {
+  background-color: #ec652d;
+  height: 3.5625rem;
+  line-height: 3.5625rem;
+  color: #fff;
+  padding: 0 1.875rem;
+  border-radius: 0.3125rem;
+  font-size: 1.125rem;
+  font-weight: bold;
+}
+
+.search-body {
+  background-color: #fff;
+  margin: 1.25rem 0;
+}
+
+.interface-table {
+  height: calc(100% - 17.1875rem);
+  overflow-x: hidden;
+  background-color: #fff;
+  padding: 0 1.125rem 2.375rem;
+  box-sizing: border-box;
+}
+
+.zan-con {
+  display: flex;
+  width: 100%;
+  justify-content: space-around;
+  margin-top: 1.5rem;
+  text-align: center;
+  font-size: 1.125rem;
+}
+
+.zan-con .line {
+  height: 8rem;
+  width: 0.0625rem;
+  background: #ccc;
+}
+
+.zan-con .zan-contain {
+  display: flex;
+  justify-content: space-between;
+  flex-direction: column;
+}
+
+.zan-con .zan-contain p {
+  font-size: 2.25rem;
+}
+
+.zan-con .zan-contain p:first-child {
+  font-size: 0.875rem;
+  line-height: 1.5;
+}
+
+.zan-sub {
+  text-align: right;
+  margin-top: 1.25rem;
+  color: #a5a5a5;
+  font-size: 0.875rem;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+
+.o-span {
+  cursor: pointer;
+  color: rgb(7, 152, 244);
+}
+
+.collection-con {
+  width: 100%;
+  overflow-x: hidden;
+  overflow-y: auto;
+  height: 60vh;
+}
+
+.collection-con ul {
+  display: flex;
+  flex-wrap: wrap;
+  margin-top: 1.25rem;
+}
+
+.collection-con ul li {
+  width: 24%;
+  margin-right: 1%;
+  cursor: pointer;
+  font-size: 0.8rem;
+  color: #2d2d2d;
+  margin-bottom: 1.25rem;
+}
+
+.collection-con ul .li-img {
+  position: relative;
+  height: 250px;
+  font-size: 0;
+}
+
+.collection-con ul .elchbox {
+  position: absolute;
+  left: 10px;
+  top: 5px;
+}
+
+.collection-con ul .li-img div span {
+  margin-right: 0.625rem;
+}
+
+.collection-con ul img {
+  width: 100%;
+}
+
+.collection-con {
+  li {
+    position: relative;
+    .li-txt {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      background: #dedede;
+      font-size: 16px;
+      line-height: 2;
+    }
+    .oper {
+      position: absolute;
+      top: 10px;
+      right: 10px;
+      display: none;
+      > img {
+        width: 40px;
+        height: 40px;
+        background: #b63c25;
+        margin-left: 20px;
+        border-radius: 4px;
+        padding: 5px;
+      }
+    }
+    &:hover {
+      .oper {
+        display: block;
+      }
+    }
+  }
+}
+
+.add-con {
+  display: flex;
+  justify-content: space-between;
+}
+
+.add-left {
+  flex: 1;
+}
+
+.add-right {
+  flex: 1;
+  margin-left: 10%;
+}
+</style>
+
+<style>
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  /* height: 178px; */
+  display: block;
+}
+
+.el-textarea__inner {
+  padding-right: 60px !important;
+}
+</style>

+ 374 - 0
src/pages/edit/carousel.vue

@@ -0,0 +1,374 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData" :status="form.status">
+      <div slot="con" class="con-btn">
+        <el-button type="primary" @click="back">返回</el-button>
+      </div>
+    </main-top>
+    <div class="reason" v-if="form.status===3">审核不通过原因:{{form.reason}}</div>
+    <div class="edit-body">
+      <div
+        class="edit-arch"
+        :style="{height: form.status === 3?`calc(100% - 11.5rem - 20px)`:`calc(100% - 8.5rem - 20px)`}"
+      >
+        <div class="title">基本信息:</div>
+        <el-form
+          ref="partform"
+          :rules="rules"
+          :model="form"
+          label-width="120px"
+          :disabled="form.status===2||form.status===4"
+        >
+          <el-form-item label="标题" style="width:618px;" prop="title">
+            <el-input
+              placeholder="请输入标题"
+              :maxlength="FONTLENGTH*0.6"
+              show-word-limit
+              v-model="form.title"
+            ></el-input>
+          </el-form-item>
+
+          <el-form-item label="场景链接" style="width:618px;" prop="webSite">
+            <el-input placeholder="请输入场景链接" v-model="form.webSite"></el-input>
+          </el-form-item>
+
+          <el-form-item label="封面图片" prop="img">
+            <el-upload
+              class="avatar-uploader"
+              :class="{'noCursor':(($role=='sys_admin'||$role=='sys_high')&&(form.status===2||form.status===4))}"
+              :action="uploadUrl"
+              :headers="{
+              token,
+            }"
+              :show-file-list="false"
+              :on-success="handleThumbSuccess"
+              :on-error="handleError"
+              :before-upload="beforeAvatarUpload"
+            >
+              <img v-if="form.thumb" :src="form.thumb" class="avatar" />
+              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+            </el-upload>
+            <span
+              style="color:#999"
+              v-if="!(($role=='sys_admin'||$role=='sys_high')&&(form.status===2||form.status===4))"
+            >支持png、jpg、gif和jpeg的图片格式;最大支持20M。</span>
+          </el-form-item>
+        </el-form>
+        <el-form label-width="120px" v-if="$role=='sys_admin'||$role=='sys_high'">
+          <el-form-item
+            v-if="($role=='sys_admin'||$role=='sys_high')&&(form.status===2||form.status===4)"
+            label="显示设置"
+          >
+            <el-switch
+              v-model="display"
+              inactive-color="#ccc"
+              @change="changeState({id:form.id,display:display})"
+            ></el-switch>
+          </el-form-item>
+        </el-form>
+      </div>
+      <div class="btnclass" v-if="form.status !== 4">
+        <template v-if="form.status!==2">
+          <el-button @click="save(1)">保存</el-button>
+          <el-button type="primary" @click="save(2)">提交</el-button>
+        </template>
+        <template v-else>
+          <template v-if="$role=='sys_admin'||$role=='sys_high'">
+            <el-button @click="dialogFormVisible = true">审核不通过</el-button>
+            <el-button type="primary" @click="()=>{reason='',examine(4)}">审核通过</el-button>
+          </template>
+        </template>
+      </div>
+    </div>
+    <el-dialog title="审核不通过" :visible.sync="dialogFormVisible">
+      <el-form :model="form">
+        <el-form-item
+          label="选择原因"
+          :rules="[
+          { required: true, message: '选择原因不能为空'},
+        ]"
+        >
+          <el-radio-group v-model="reason">
+            <el-radio :label="'信息内容待调整'">信息内容待调整</el-radio>
+            <el-radio :label="'标题需进行修改'">标题需进行修改</el-radio>
+            <el-radio :label="2">自定义</el-radio>
+          </el-radio-group>
+          <el-input
+            v-model="zidingyi"
+            v-if="reason===2"
+            type="textarea"
+            :autosize="{ minRows: 2, maxRows: 4}"
+          ></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+        <el-button type="primary" @click="examine(3)">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from "@/components/main-top";
+import { changeState } from "@/util/commonfn.js";
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+  },
+  data() {
+    const crumbData = [
+      {
+        name: "史馆动态信息",
+        id: 0,
+      },
+      {
+        name: this.$route.params.type ? "编辑史馆动态" : "新增史馆动态",
+        id: 1,
+      },
+    ];
+
+    return {
+      crumbData,
+      reason: "信息内容待调整",
+      zidingyi: "",
+      dialogFormVisible: false,
+      form: {
+        id: "",
+        img: "",
+        thumb: "",
+        title: "",
+        webSite: "",
+      },
+      display: true,
+      type: this.$route.params.type,
+      id: this.$route.params.id,
+      token: window.localStorage.getItem("token"),
+      uploadUrl: `${this.$serverName}manage/file/upload`,
+      rules: {
+        title: [{ required: true, message: "请输入标题", trigger: "blur" }],
+        webSite: [
+          { required: true, message: "请输入场景链接", trigger: "blur" },
+        ],
+        img: [{ required: true, message: "请上传封面图片", trigger: "blur" }],
+      },
+    };
+  },
+  methods: {
+    back() {
+      if(this.form.status===2){
+          this.$router.back();
+      }
+      else{
+        this.$confirm("点击返回后, 编辑的信息将无法保存,是否继续?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }).then(() => {
+          this.$router.back();
+        });
+      }
+    },
+    changeState(item) {
+      changeState(item, "slideshow");
+    },
+
+    async examine(status) {
+      this.$confirm("请再次确认是否进行此审核操作?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(async () => {
+          let result = await this.$http({
+            method: "post",
+            data: {
+              id: this.form.id,
+              reason: this.reason === 2 ? this.zidingyi : this.reason,
+              status,
+            },
+            headers: {
+              token: window.localStorage.getItem("token"),
+            },
+            url: `/manage/slideshow/audit`,
+          });
+
+          if (result.code === 0) {
+            this.$alert("审核成功", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+                this.$router.back();
+              },
+            });
+          } else {
+            this.$notify.error({
+              title: "错误",
+              message: result.msg,
+            });
+          }
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消",
+          });
+        });
+    },
+    handleError(){
+      this.$alert("上传失败,请稍后再试", "提示", {
+        confirmButtonText: "确定",
+        callback: () => {
+          this.loading.close()
+        },
+      });
+    },
+    handleThumbSuccess(res) {
+      this.loading.close();
+      let { data } = res;
+      this.form.thumb = data.thumb;
+      this.form.img = data.urlPath;
+    },
+    beforeAvatarUpload(file) {
+      let type = this.isImage(file.name);
+      if (!type) {
+        this.$message.error("只允许上传图片");
+        return type;
+      }
+      const isLt2M = file.size / 1024 / 1024 < 20;
+
+      if (!isLt2M) {
+        this.$message.error("上传头像图片大小不能超过 20MB!");
+        return isLt2M;
+      }
+      this.loading = this.$loading(this.loadOption);
+    },
+
+    async postStatus(status){
+       let { id = "", img, thumb, title, webSite } = this.form;
+          let params = {
+            id,
+            img,
+            thumb,
+            title,
+            webSite,
+            status,
+          };
+          let result = await this.$http({
+            method: "post",
+            data: params,
+            headers: {
+              token: window.localStorage.getItem("token"),
+            },
+            url: `/manage/slideshow/save`,
+          });
+
+          if (result.code === 0) {
+            this.$alert("操作成功", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+                this.$router.back();
+              },
+            });
+          } else {
+            this.$notify.error({
+              title: "错误",
+              message: result.msg,
+            });
+          }
+    },
+
+    save(status) {
+      this.$refs["partform"].validate(async (valid) => {
+        if (valid) {
+          if(status == 2){
+             this.$confirm("请再次确认是否进行此审核操作?", "提示", {
+                confirmButtonText: "确定",
+                cancelButtonText: "取消",
+                type: "warning",
+              }).then(async () => {
+                  this.postStatus(status)
+                  })
+                .catch(() => {
+                  this.$message({
+                    type: "info",
+                    message: "已取消",
+                  });
+                });
+          }
+          else{
+            this.postStatus(status)
+          }         
+        }
+      });
+    },
+    async getDetail() {
+      let result = await this.$http({
+        method: "get",
+        headers: {
+          token: window.localStorage.getItem("token"),
+        },
+        url: `/manage/slideshow/detail/${this.id}`,
+      });
+
+      this.form = result.data;
+      this.display = Boolean(this.form.display);
+    },
+  },
+  mounted() {
+    if (this.id && this.id !== "none") {
+      this.getDetail();
+    }
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.edit-body {
+  background: #fff;
+  height: 100%;
+  .edit-arch {
+    overflow-y: auto;
+    overflow-x: hidden;
+    height: calc(100% - 8.5rem - 20px);
+    background-color: #fff;
+    padding: 20px 40px 20px 20px;
+  }
+  .btnclass {
+    text-align: center;
+    border: 1px solid #ccc;
+    padding: 10px 0;
+    width: calc(100% - 80px);
+    margin: 0 auto;
+  }
+}
+</style>
+<style>
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  /* height: 178px; */
+  display: block;
+}
+</style>

+ 710 - 0
src/pages/edit/collection.vue

@@ -0,0 +1,710 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData" :status="form.status">
+      <div slot="con" class="con-btn">
+        <el-button type="primary" @click="back">返回</el-button>
+      </div>
+    </main-top>
+    <div class="reason" v-if="form.status===3">
+      审核不通过原因:{{form.reason}}
+    </div>
+    <div class="edit-body">
+      <div class="edit-arch" :style="{height: form.status === 3?`calc(100% - 11.5rem - 20px)`:`calc(100% - 8.5rem - 20px)`}">
+        <div class="title">基本信息:</div>
+        <el-form ref="partform" :rules="rules" :model="form" label-width="120px" :disabled="form.status===2||(!($role=='sys_admin'||$role=='sys_high')&&(form.status===4))">
+          <el-form-item label="标题" prop="title">
+            <el-input
+              placeholder="请输入标题"
+              :maxlength="FONTLENGTH"
+              show-word-limit
+              v-model="form.title"
+              :disabled="form.status===2||(!($role=='sys_admin'||$role=='sys_high')&&(form.status===4))"
+            ></el-input>
+          </el-form-item>
+
+          <el-form-item label="精品类型" prop="type">
+            <el-radio-group :disabled="$route.params.type==1" v-model="form.type">
+              <el-radio :label="3">实物模型</el-radio>
+              <el-radio :label="1">专题图库</el-radio>
+              <el-radio :label="2">视频档案</el-radio>
+            </el-radio-group>
+          </el-form-item>
+
+          <template v-if="form.type === 3">
+            <el-form-item label="封面图片" prop="thumb">
+              <el-upload
+                :disabled="form.status===2||(!($role=='sys_admin'||$role=='sys_high')&&(form.status===4))"
+                class="avatar-uploader"
+                :action="uploadUrl"
+                :headers="{token}"
+                :class="{'noCursor':(($role=='sys_admin'||$role=='sys_high')&&(form.status===2))}"
+                :show-file-list="false"
+                :on-success="handleThumbSuccess"
+                :on-error="handleError"
+                :before-upload="beforeAvatarUpload"
+              >
+                <img v-if="form.thumb" :src="form.thumb" class="avatar" />
+                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              </el-upload>
+              <span style="color:#999"
+              v-if="!(($role=='sys_admin'||$role=='sys_high')&&(form.status===2))"
+              >支持png、jpg、gif和jpeg的图片格式;最大支持20M。</span>
+            </el-form-item>
+          
+
+            <el-form-item label="模型文件" required :key="'moxing'">
+              <el-upload
+                class="upload-demo"
+                drag
+                :disabled="form.status===2||(!($role=='sys_admin'||$role=='sys_high')&&(form.status===4))"
+                :action="uploadModelUrl"
+                :headers="{token}"
+                :show-file-list="false"
+                :before-upload="beforeMultipleUpload"
+                :on-error="handleError"
+                :on-success="handleSuccess"
+              >
+                <i class="el-icon-upload"></i>
+                <div class="el-upload__text">
+                  将文件拖到此处,或
+                  <em>点击上传</em>
+                  <p>仅支持.4dage格式的模型文件,大小不得超过500m</p>
+                </div>
+              </el-upload>
+              <p v-if="filesIds[0]" style="color:#999">{{filesIds[0].fileName}}</p>
+            </el-form-item>
+
+              <el-form-item label="模型介绍">
+              <el-input
+                placeholder="请输入模型介绍"
+                :maxlength="250"
+                show-word-limit
+                type="textarea"
+                v-model="form.description"
+              ></el-input>
+            </el-form-item>
+          </template>
+
+          <template v-else-if="form.type === 1">
+            <el-form-item label="年份" required :key="'tukuyear'">
+              <el-select v-model="form.year" placeholder="请选择">
+                <el-option v-for="(item,i) in yearStr" :key="i" :label="item.name" :value="item.id"></el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item label="专题图库"  required :key="'tuku'">
+              <el-upload
+                :action="uploadUrl"
+                :disabled="form.status===2||(!($role=='sys_admin'||$role=='sys_high')&&(form.status===4))"
+                :headers="{token}"
+                list-type="picture-card"
+                :file-list="fileList"
+                :before-upload="beforeAvatarUpload"
+                  multiple
+                :on-error="handleError"
+                :on-success="handlePictureCardSuccess"
+              >
+
+                <i class="el-icon-plus"></i>
+                <div class="card-con" slot="file" slot-scope="{file}">
+                  <img
+                    class="el-upload-list__item-thumbnail"
+                    :src="file.url" alt=""
+                  >
+                  <span class="el-upload-list__item-actions">
+                    <span
+                      class="el-upload-list__item-delete"
+                    >
+                      <i v-if="form.status!==2" class="el-icon-delete" @click="del(file)"></i>
+                    </span>
+                  </span>
+                  <div class="cover" v-if="file.cover">封面图片</div>
+                  <div class="btn-con">
+                
+                    <el-button class="queren" :disabled="form.status===2||(!($role=='sys_admin'||$role=='sys_high')&&(form.status===4))" v-if="!file.cover" @click="setCover(file)" size="mini" type="primary">设为封面</el-button>
+                    <!-- <el-upload
+                      :action="uploadUrl"
+                      :headers="{token}"
+                      :on-success="handleReloadSuccess"
+                      :before-upload="showLoading"
+                      :disabled="form.status===2"
+                      :show-file-list="false">
+                      <el-button @click="reupload(file)" size="mini">重新上传</el-button>
+                    </el-upload> -->
+                  </div>
+                </div>
+              </el-upload>
+              <div style="color:#999;margin-top:40px" >格式要求:支持png、jpg、gif和jpeg的图片格式;最大支持20M;最多可以上传18张图片</div>
+            </el-form-item>
+          </template>
+
+          <template v-else>
+            <el-form-item label="年份" required :key="'shipinyear'">
+              <el-select v-model="form.year" placeholder="请选择">
+                <el-option v-for="(item,i) in yearStr" :key="i" :label="item.name" :value="item.id"></el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item label="封面图片" prop="thumb" >
+              <el-upload
+                class="avatar-uploader"
+                :action="uploadUrl"
+                :headers="{token}"
+                :class="{'noCursor':(($role=='sys_admin'||$role=='sys_high')&&(form.status===2))}"
+                :disabled="form.status===2||(!($role=='sys_admin'||$role=='sys_high')&&(form.status===4))"
+                :show-file-list="false"
+                :on-success="handleThumbSuccess"
+                :on-error="handleError"
+                :before-upload="beforeAvatarUpload"
+              >
+                <img v-if="form.thumb" :src="form.thumb" class="avatar" />
+                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              </el-upload>
+              <span style="color:#999"
+                v-if="!(($role=='sys_admin'||$role=='sys_high')&&(form.status===2))"
+              >支持png、jpg、gif和jpeg的图片格式;最大支持20M。</span>
+            </el-form-item>
+
+             <el-form-item label="视频文件" required :key="'shipin'">
+              <el-upload
+                class="upload-demo"
+                drag
+                :action="uploadUrl"
+                :disabled="form.status===2||(!($role=='sys_admin'||$role=='sys_high')&&(form.status===4))"
+                :headers="{token}"
+                :show-file-list="false"
+                :before-upload="beforeMultipleUpload"
+                :on-error="handleError"
+                :on-success="handleSuccess"
+              >
+                <i class="el-icon-upload"></i>
+                <div class="el-upload__text">
+                  将文件拖到此处,或
+                  <em>点击上传</em>
+                  <p style="padding:0 10px;">支持AVI、mov、rmvb、rm、FLV、mp4、3GP等格式的视频文件,大小不得超过2GB</p>
+                </div>
+              </el-upload>
+              <p v-if="filesIds[0]" style="color:#999">{{filesIds[0].fileName}}</p>
+            </el-form-item>
+          </template>
+        </el-form>
+        <el-form
+          label-width="120px"
+          v-if="$role=='sys_admin'||$role=='sys_high'"
+        >
+          <el-form-item v-if="($role=='sys_admin'||$role=='sys_high')&&(form.status===2)" label="显示设置">
+            <el-switch v-model="display" inactive-color="#ccc" @change="changeState({id:form.id,display:display})">
+          </el-switch>
+          </el-form-item>
+        </el-form>
+      </div>
+      <template v-if="form.status !== 4">
+        <div class="btnclass" v-if="form.status!==2">
+          <el-button @click="save(1)">保存</el-button>
+          <el-button type="primary" @click="save(2)">提交</el-button>
+        </div>
+        <template  v-else>
+          <div class="btnclass" v-if="$role=='sys_admin'||$role=='sys_high'">
+            <el-button @click="dialogFormVisible = true">审核不通过</el-button>
+            <el-button type="primary" @click="()=>{reason='',examine(4)}">审核通过</el-button>
+          </div>
+        </template>
+      </template>
+      <template v-if="form.status === 4 && $role=='sys_admin'||$role=='sys_high'">
+        <div class="btnclass">
+          <el-button @click="save(1)">保存</el-button>
+          <el-button type="primary" @click="save(2)">提交</el-button>
+        </div>
+      </template>
+    </div>
+    <el-dialog title="审核不通过" :visible.sync="dialogFormVisible">
+      <el-form :model="form" >
+        <el-form-item label="选择原因" :rules="[
+          { required: true, message: '选择原因不能为空'},
+        ]" >
+            <el-radio-group v-model="reason">
+              <el-radio :label="'信息内容待调整'">信息内容待调整</el-radio>
+              <el-radio :label="'标题需进行修改'">标题需进行修改</el-radio>
+              <el-radio :label="2">自定义</el-radio>
+            </el-radio-group>
+            <el-input v-model="zidingyi" v-if="reason===2" type="textarea" :autosize="{ minRows: 2, maxRows: 4}"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+        <el-button type="primary" @click="examine(3)">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from "@/components/main-top";
+import {changeState} from '@/util/commonfn.js'
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop
+  },
+  watch:{
+    'form.type':function (newVal) {
+      if (this.type==0) {
+        this.form={
+          fileIds: "",
+          description:"",
+          id: '',
+          thumb: "",
+          thumbFileId:'',
+          title: "",
+          type: newVal,
+          year: 2020
+        }
+      this.filesIds=[]
+      }
+    }
+  },
+  data() {
+    const crumbData = [
+      {
+        name: "精品典藏信息",
+        id: 0
+      },
+      {
+        name: this.$route.params.type ? "编辑精品典藏" : "新增精品典藏",
+        id: 1
+      }
+    ];
+
+    return {
+      crumbData,
+      reason:'信息内容待调整',
+      zidingyi:'',
+      dialogFormVisible:false,
+      currentIdx:1,
+      form: {
+        fileIds: "",
+        description:"",
+        id: '',
+        thumb: "",
+        thumbFileId:'',
+        title: "",
+        year:2020,
+        type: parseInt(this.$route.query.type)
+      },
+      display: true,
+      filesIds:[],
+      fileList: [],
+      type: this.$route.params.type,
+      id: this.$route.params.id,
+      token: window.localStorage.getItem("token"),
+      uploadUrl: `${this.$serverName}manage/file/upload?compress=1`,
+      uploadModelUrl: `${this.$serverName}manage/goods/upload`,
+      rules: {
+        title: [{ required: true, message: "请输入标题", trigger: "blur" }],
+        type: [{ required: true, message: "请选择精品类型", trigger: "blur" }],
+        thumb: [{ required: true, message: "请上传封面图片", trigger: "blur" }],
+      }
+    };
+  },
+  methods: {
+    showLoading(){
+      this.loading = this.$loading(this.loadOption)
+    },
+    back() {
+      if(this.form.status===2){
+          this.$router.back();
+      }
+      else{
+        this.$confirm("点击返回后, 编辑的信息将无法保存,是否继续?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }).then(() => {
+          this.$router.back();
+        });
+      }
+    },
+    changeState(item) {
+      changeState(item,'goods')
+    },
+     del (item) {
+      this.$confirm('删除后,信息将无法恢复,是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http.get(`/manage/file/remove/${item.id}`,{headers: {
+          token: window.localStorage.getItem('token')
+        }}).then(res => {
+          if (res.code === 0) {
+            this.$alert('删除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: () => {
+                let tmp = []
+                this.fileList.forEach(sub => {
+                  if (sub.id === item.id) {
+                    return 
+                  }
+                  tmp.push(sub)
+                });
+                this.fileList = tmp
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.msg
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    async setCover(item){
+      let {id} = item
+      this.fileList.forEach((sub) => {
+          if (sub.id == id) {
+              sub.cover = true
+          }
+          else{
+              sub.cover = false
+          }
+      });
+    },
+    async examine(status) {
+      this.$confirm("请再次确认是否进行此审核操作?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(async () => {
+          let result = await this.$http({
+            method: "post",
+            data: {
+              id: this.form.id,
+              reason: this.reason === 2 ? this.zidingyi : this.reason,
+              status,
+            },
+            headers: {
+              token: window.localStorage.getItem("token"),
+            },
+            url: `/manage/goods/audit`,
+          });
+
+          if (result.code === 0) {
+            this.$alert("审核成功", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+                this.$router.back();
+              },
+            });
+          } else {
+            this.$notify.error({
+              title: "错误",
+              message: result.msg,
+            });
+          }
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消",
+          });
+        });
+    },
+    // reupload(item){
+    //   this.activeFlie = item
+    // },
+    // handleReloadSuccess(res){
+    //   this.loading.close()
+    //   let { data } = res;
+    //   let activeIdx = ''
+    //   this.fileList.forEach((sub,i) => {
+    //     if (sub.id == this.activeFlie.id) {
+    //       activeIdx = i
+    //     }
+    //   });
+
+    //   this.fileList.splice(activeIdx,1,{
+    //     url: data.urlPath,
+    //     name: data.fileName,
+    //     id: data.id,
+    //     cover:data.cover
+    //   });
+    // },
+    handlePictureCardSuccess(res){
+      this.currentIdx += 1
+      let cuidx = this.currentIdx
+      this.loading.close()
+      let { data } = res;
+      setTimeout(() => {
+        this.fileList.push({
+          url: data.urlPath,
+          name: data.fileName,
+          id: data.id,
+          cover:data.cover
+        }); 
+      }, 1000 + 100 * cuidx);
+    },
+    handleThumbSuccess(res) {
+      this.loading.close()
+      let { data } = res;
+      this.form.thumb = data.thumb;
+    },
+    handleError(){
+      this.$alert("上传失败,请稍后再试", "提示", {
+        confirmButtonText: "确定",
+        callback: () => {
+          this.loading.close()
+        },
+      });
+    },
+    beforeAvatarUpload(file) {
+      this.currentIdx = 0
+      let type = this.isImage(file.name);
+      if (!type) {
+        this.$message.error('只允许上传图片');
+        return type
+      }
+      const isLt2M = file.size / 1024 / 1024 < 20;
+      if (!isLt2M) {
+        this.$message.error("上传头像图片大小不能超过 20MB!");
+        return isLt2M;
+      }
+      this.showLoading()
+
+    },
+
+    handleSuccess(res) {
+      this.loading.close()
+      let { data } = res;
+      if (this.form.type !== 1) {
+        this.filesIds = []
+      }
+      this.filesIds.push(data)
+    },
+
+    beforeMultipleUpload(file){
+      let typeArr = this.form.type !== 2 ? ['.4dage'] : ['avi','mov','rmvb','rm','flv','mp4','3gp']
+      let type = this.isTypeBySend(file.name,typeArr);
+      if (!type) {
+        this.$message.error('只允许指定文件格式的文件');
+        return type
+      }
+      
+      let size = this.form.type === 2 ? 2000 : 500
+      const isLt500M = file.size / 1024 / 1024 < size;
+
+      if (!isLt500M) {
+        this.$message.error(`上传文件大小不能超过 ${size}MB!`);
+        return isLt500M;
+      }
+      this.showLoading()
+    },
+
+    
+    async postStatus(status){
+      let { id = "", thumb, title, fileUrl,year,description, type } = this.form;
+          let ids = type === 1 ? this.fileList : this.filesIds;
+          let thumbFileId = this.fileList.filter((item) => item.cover);
+          if(type === 1){
+            if(thumbFileId.length<=0){
+              return this.$notify.error({
+                title: "错误",
+                message: '请设置封面图片',
+              });
+            }
+          }
+          if(ids.length <= 0){
+            return this.$notify.error({
+              title: "错误",
+              message: `${this.collectType[type]}不能为空`,
+            });
+          }
+          let params = {
+            fileIds: ids.map((item) => item.id).join(","),
+            id,
+            description,
+            thumb,
+            title,
+            thumbFileId: thumbFileId.length > 0 ? thumbFileId[0].id : "",
+            type,
+            fileUrl,
+            status,
+            year
+          };
+          let result = await this.$http({
+            method: "post",
+            data: params,
+            headers: {
+              token: window.localStorage.getItem("token"),
+            },
+            url: `/manage/goods/save`,
+          });
+
+          if (result.code === 0) {
+            this.$alert("操作成功", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+                this.$router.back();
+              },
+            });
+          } else {
+            this.$notify.error({
+              title: "错误",
+              message: result.msg,
+            });
+          }
+    },
+
+    save(status) {
+      this.$refs["partform"].validate(async (valid) => {
+        if (valid) {
+         if(status == 2){
+             this.$confirm("请再次确认是否进行此审核操作?", "提示", {
+                confirmButtonText: "确定",
+                cancelButtonText: "取消",
+                type: "warning",
+              }).then(async () => {
+                  this.postStatus(status)
+                  })
+                .catch(() => {
+                  this.$message({
+                    type: "info",
+                    message: "已取消",
+                  });
+                });
+          }
+          else{
+            this.postStatus(status)
+          }         
+        }
+      });
+    },
+
+    async getDetail() {
+      let result = await this.$http({
+        method: "get",
+        headers: {
+          token: window.localStorage.getItem("token")
+        },
+        url: `/manage/goods/detail/${this.id}`
+      });
+
+      this.form = result.data.entity;
+
+      this.form.year = this.form.year || 2020
+      this.display = Boolean(this.form.display)
+      this.filesIds = result.data.file;
+      this.fileList = result.data.file.map((item) => {
+        return {
+          name: item.fileName,
+          url: item.urlPath,
+          id: item.id,
+          cover: item.cover
+        };
+      });
+    }
+  },
+  mounted() {
+    if (this.id && this.id !== "none") {
+      this.getDetail();
+    }
+    else{
+      setTimeout(() => {
+        this.fileList = []
+      });
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+.edit-body {
+  background: #fff;
+  height: 100%;
+  .edit-arch {
+    overflow-y: auto;
+    overflow-x: hidden;
+    height: calc(100% - 8.5rem - 20px);
+    background-color: #fff;
+    padding: 20px 40px 20px 20px;
+  }
+  .btnclass {
+    text-align: center;
+    border: 1px solid #ccc;
+    padding: 10px 0;
+    width: calc(100% - 80px);
+    margin: 0 auto;
+  }
+}
+</style>
+<style lang="less">
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  /* height: 178px; */
+  display: block;
+}
+.el-upload-list--picture-card .el-upload-list__item{
+  overflow: visible!important;
+  margin-top: 40px;
+}
+
+.el-upload--picture-card{
+  margin-top: 40px;
+}
+
+.card-con{
+  height: 100%;
+  position: relative;
+  .btn-con{
+    position: absolute;
+    justify-content: center;
+    bottom: -40px;
+    display: flex;
+    width: 100%;
+    .queren{
+      margin-right: 4px!important;
+    }
+    .el-button--mini, .el-button--mini.is-round{
+      padding: 7px 10px!important;
+    }
+  }
+
+  .cover{
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    background-color: rgba(0, 0, 0, 0.4);
+    width: 100%;
+    padding: 4px 0;
+    color: #fff;
+    text-align: center;
+    pointer-events: none;
+  }
+}
+</style>

+ 447 - 0
src/pages/edit/dynamic.vue

@@ -0,0 +1,447 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData" :status="form.status">
+      <div slot="con" class="con-btn">
+        <el-button type="primary" @click="back">返回</el-button>
+      </div>
+    </main-top>
+    <div class="reason" v-if="form.status===3">审核不通过原因:{{form.reason}}</div>
+    <div class="edit-body">
+      <div
+        class="edit-arch"
+        :style="{height: form.status === 3?`calc(100% - 11.5rem - 20px)`:`calc(100% - 8.5rem - 20px)`}"
+      >
+        <div class="title">基本信息:</div>
+        <el-form
+          ref="partform"
+          :rules="rules"
+          :model="form"
+          label-width="120px"
+          :disabled="form.status===2||form.status===4"
+        >
+          <el-form-item label="动态类型" prop="type">
+            <el-radio-group v-model="form.type">
+              <el-radio :label="'news'">新闻</el-radio>
+              <el-radio :label="'notice'">公告</el-radio>
+            </el-radio-group>
+          </el-form-item>
+
+          <el-form-item label="标题" prop="title">
+            <el-input
+              placeholder="请输入标题"
+              :maxlength="FONTLENGTH"
+              show-word-limit
+              v-model="form.title"
+            ></el-input>
+          </el-form-item>
+
+          <el-form-item label="作者" prop="author">
+            <el-input
+              placeholder="请输入作者"
+              :maxlength="30"
+              show-word-limit
+              v-model="form.author"
+            ></el-input>
+          </el-form-item>
+
+          <el-form-item label="封面图片">
+            <el-upload
+              :class="{'noCursor':(($role=='sys_admin'||$role=='sys_high')&&(form.status===2||form.status===4))}"
+              class="avatar-uploader"
+              :action="uploadUrl"
+              :headers="{
+                token,
+              }"
+              :show-file-list="false"
+              :on-success="handleThumbSuccess"
+              :on-error="handleError"
+              :before-upload="beforeAvatarUpload"
+            >
+              <img v-if="form.img" :src="form.img" class="avatar" />
+              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+            </el-upload>
+            <span
+              style="color:#999"
+              v-if="!(($role=='sys_admin'||$role=='sys_high')&&(form.status===2||form.status===4))"
+            >支持png、jpg、gif和jpeg的图片格式;最大支持20M。</span>
+          </el-form-item>
+
+          <el-form-item label="单位">
+            <el-input
+              type="textarea"
+              :maxlength="MAXLENGTH * 0.25"
+              show-word-limit
+              v-model="form.description"
+            ></el-input>
+          </el-form-item>
+        </el-form>
+        <el-form label-width="120px" v-if="$role=='sys_admin'||$role=='sys_high'">
+          <el-form-item
+            v-if="($role=='sys_admin'||$role=='sys_high')&&(form.status===2||form.status===4)"
+            label="显示设置"
+          >
+            <el-switch
+              v-model="display"
+              inactive-color="#ccc"
+              @change="changeState({id:form.id,display:display})"
+            ></el-switch>
+          </el-form-item>
+        </el-form>
+
+        <div class="main-title">
+          <div class="title">信息正文:</div>
+          <div class="text-con" v-if="form.status===2||form.status===4" v-html="form.content"></div>
+          <!-- <Editor @onchange="data=>{form.content = data}" v-else :content="form.content"></Editor> -->
+          <tinymce
+            v-else
+            ref="tinymce"
+            :height="500"
+            :htmlstr="form.content"
+            @blur="handleBlur"
+            />
+        </div>
+      </div>
+      <div class="btnclass" v-if="form.status !== 4">
+        <template v-if="form.status!==2">
+          <el-button @click="save(1)">保存</el-button>
+          <el-button type="primary" @click="save(2)">提交</el-button>
+        </template>
+        <template v-else>
+          <template v-if="$role=='sys_admin'||$role=='sys_high'">
+            <el-button @click="dialogFormVisible = true">审核不通过</el-button>
+            <el-button type="primary" @click="()=>{reason='',examine(4)}">审核通过</el-button>
+          </template>
+        </template>
+      </div>
+    </div>
+
+    <el-dialog title="审核不通过" :visible.sync="dialogFormVisible">
+      <el-form :model="form">
+        <el-form-item
+          label="选择原因"
+          :rules="[
+          { required: true, message: '选择原因不能为空'},
+        ]"
+        >
+          <el-radio-group v-model="reason">
+            <el-radio :label="'信息内容待调整'">信息内容待调整</el-radio>
+            <el-radio :label="'标题需进行修改'">标题需进行修改</el-radio>
+            <el-radio :label="2">自定义</el-radio>
+          </el-radio-group>
+          <el-input
+            v-model="zidingyi"
+            v-if="reason===2"
+            type="textarea"
+            :autosize="{ minRows: 2, maxRows: 4}"
+          ></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+        <el-button type="primary" @click="examine(3)">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from "@/components/main-top";
+// import Editor from "@/components/Editor";
+import Tinymce from "@/components/Tinymce/index.vue";
+
+
+import { changeState } from "@/util/commonfn.js";
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+    // Editor,
+    Tinymce
+  },
+  computed: {
+    crumbData() {
+      return [
+        {
+          name: "史馆动态信息",
+          id: 0,
+        },
+        {
+          name: this.$route.params.type
+            ? this.form.status !== 2 || this.form.status !== 4
+              ? "史馆动态"
+              : "编辑史馆动态"
+            : "新增史馆动态",
+          id: 1,
+        },
+      ];
+    },
+  },
+  data() {
+    return {
+      reason: "信息内容待调整",
+      zidingyi: "",
+      dialogFormVisible: false,
+      display: true,
+      form: {
+        content: "",
+        description: "",
+        display: false,
+        id: "",
+        img: "",
+        thumb: "",
+        author:"",
+        title: "",
+        type: "news",
+      },
+      type: this.$route.params.type,
+      id: this.$route.params.id,
+      token: window.localStorage.getItem("token"),
+      uploadUrl: `${this.$serverName}manage/file/upload`,
+      rules: {
+        type: [{ required: true, message: "请选择动态类型", trigger: "blur" }],
+        author: [{ required: true, message: "请输入作者", trigger: "blur" }],
+        title: [{ required: true, message: "请输入标题", trigger: "blur" }],
+        img: [{ required: true, message: "请上传封面图片", trigger: "blur" }],
+      },
+    };
+  },
+  methods: {
+    handleBlur(data){
+      this.form.content = data
+    },
+    getContent(data){
+      console.log(data);
+    },
+    back() {
+      if(this.form.status===2){
+          this.$router.back();
+      }
+      else{
+        this.$confirm("点击返回后, 编辑的信息将无法保存,是否继续?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }).then(() => {
+          this.$router.back();
+        });
+      }
+    },
+    changeState(item) {
+      changeState(item, "news");
+    },
+    handleError(){
+      this.$alert("上传失败,请稍后再试", "提示", {
+        confirmButtonText: "确定",
+        callback: () => {
+          this.loading.close()
+        },
+      });
+    },
+    handleThumbSuccess(res) {
+      this.loading.close();
+      let { data } = res;
+
+      this.form.img = data.urlPath;
+      this.form.thumb = data.thumb;
+    },
+    beforeAvatarUpload(file) {
+      let type = this.isImage(file.name);
+      if (!type) {
+        this.$message.error("只允许上传图片");
+        return type;
+      }
+      const isLt2M = file.size / 1024 / 1024 < 20;
+
+      if (!isLt2M) {
+        this.$message.error("上传头像图片大小不能超过 20MB!");
+        return isLt2M;
+      }
+      this.loading = this.$loading(this.loadOption);
+    },
+
+    async examine(status) {
+      this.$confirm("请再次确认是否进行此审核操作?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(async () => {
+          let result = await this.$http({
+            method: "post",
+            data: {
+              id: this.form.id,
+              reason: this.reason === 2 ? this.zidingyi : this.reason,
+              status,
+            },
+            headers: {
+              token: window.localStorage.getItem("token"),
+            },
+            url: `/manage/news/audit`,
+          });
+
+          if (result.code === 0) {
+            this.$alert("审核成功", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+                this.$router.back();
+              },
+            });
+          } else {
+            this.$notify.error({
+              title: "错误",
+              message: result.msg,
+            });
+          }
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消",
+          });
+        });
+    },
+
+    async postStatus(status){
+        let {
+            id = "",
+            content,
+            description,
+            display,
+            img,
+            thumb,
+            author,
+            title,
+            type,
+          } = this.form;
+          let params = {
+            id,
+            content,
+            description,
+            display: display * 1,
+            img,
+            thumb,
+            author,
+            title,
+            type,
+            status,
+          };
+          let result = await this.$http({
+            method: "post",
+            data: params,
+            headers: {
+              token: window.localStorage.getItem("token"),
+            },
+            url: `/manage/news/save`,
+          });
+
+          if (result.code === 0) {
+            this.$alert("操作成功", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+                this.$router.back();
+              },
+            });
+          } else {
+            this.$notify.error({
+              title: "错误",
+              message: result.msg,
+            });
+          }
+
+    },
+    save(status) {
+      this.$refs["partform"].validate(async (valid) => {
+        if (valid) {
+          if(status == 2){
+             this.$confirm("请再次确认是否进行此审核操作?", "提示", {
+                confirmButtonText: "确定",
+                cancelButtonText: "取消",
+                type: "warning",
+              }).then(async () => {
+                  this.postStatus(status)
+                  })
+                .catch(() => {
+                  this.$message({
+                    type: "info",
+                    message: "已取消",
+                  });
+                });
+          }
+          else{
+            this.postStatus(status)
+          }         
+        }
+      });
+    },
+    async getDetail() {
+      let result = await this.$http({
+        method: "get",
+        headers: {
+          token: window.localStorage.getItem("token"),
+        },
+        url: `/manage/news/detail/${this.id}`,
+      });
+
+      this.form = result.data;
+      this.display = Boolean(this.form.display);
+      this.form["display"] = Boolean(this.form["display"]);
+    },
+  },
+  mounted() {
+    if (this.id && this.id !== "none") {
+      this.getDetail();
+    }
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.edit-body {
+  background: #fff;
+  height: 100%;
+  .edit-arch {
+    overflow-y: auto;
+    overflow-x: hidden;
+    height: calc(100% - 11.5rem - 20px);
+    background-color: #fff;
+    padding: 20px 40px 20px 20px;
+  }
+
+  .btnclass {
+    text-align: center;
+    border: 1px solid #ccc;
+    padding: 10px 0;
+    width: calc(100% - 80px);
+    margin: 0 auto;
+  }
+}
+</style>
+<style>
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  /* height: 178px; */
+  display: block;
+}
+</style>

+ 422 - 0
src/pages/edit/spirit.vue

@@ -0,0 +1,422 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData" :status="form.status">
+      <div slot="con" class="con-btn">
+        <el-button type="primary" @click="back">返回</el-button>
+      </div>
+    </main-top>
+    <div class="reason" v-if="form.status===3">审核不通过原因:{{form.reason}}</div>
+    <div class="edit-body">
+      <div
+        class="edit-arch"
+        :style="{height: form.status === 3?`calc(100% - 11.5rem - 20px)`:`calc(100% - 8.5rem - 20px)`}"
+      >
+        <div class="title">基本信息:</div>
+        <el-form
+          ref="partform"
+          :rules="rules"
+          :model="form"
+          label-width="120px"
+          :disabled="form.status===2||form.status===4"
+        >
+          <el-form-item label="标题" prop="title">
+            <el-input
+              placeholder="请输入标题"
+              :maxlength="FONTLENGTH"
+              show-word-limit
+              v-model="form.title"
+            ></el-input>
+          </el-form-item>
+
+          <el-form-item label="归属单位" prop="title">
+            <el-input
+              placeholder="请输入归属单位"
+              :maxlength="FONTLENGTH * 2"
+              show-word-limit
+              v-model="form.unit"
+            ></el-input>
+          </el-form-item>
+
+          <el-form-item label="作者" prop="author">
+            <el-input
+              placeholder="请输入作者"
+              :maxlength="30"
+              show-word-limit
+              v-model="form.author"
+            ></el-input>
+          </el-form-item>
+
+          <el-form-item label="封面图片" prop="img">
+            <el-upload
+              class="avatar-uploader"
+              :class="{'noCursor':(($role=='sys_admin'||$role=='sys_high')&&(form.status===2||form.status===4))}"
+              :action="uploadUrl"
+              :headers="{
+                token,
+              }"
+              :show-file-list="false"
+              :on-success="handleThumbSuccess"
+              :on-error="handleError"
+              :before-upload="beforeAvatarUpload"
+            >
+              <img v-if="form.img" :src="form.img" class="avatar" />
+              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+            </el-upload>
+            <span
+              style="color:#999"
+              v-if="!(($role=='sys_admin'||$role=='sys_high')&&(form.status===2||form.status===4))"
+            >支持png、jpg、gif和jpeg的图片格式;最大支持20M。</span>
+          </el-form-item>
+        </el-form>
+        <el-form label-width="120px" v-if="$role=='sys_admin'||$role=='sys_high'">
+          <el-form-item
+            v-if="($role=='sys_admin'||$role=='sys_high')&&(form.status===2||form.status===4)"
+            label="显示设置"
+          >
+            <el-switch
+              v-model="display"
+              inactive-color="#ccc"
+              @change="changeState({id:form.id,display:display})"
+            ></el-switch>
+          </el-form-item>
+        </el-form>
+
+        <div class="main-title">
+          <div class="title">信息正文:</div>
+          <div class="text-con" v-if="form.status===2||form.status===4" v-html="form.content"></div>
+          <tinymce
+            v-else
+            ref="tinymce"
+            :height="500"
+            :htmlstr="form.content"
+            @blur="handleBlur"
+            />
+        </div>
+      </div>
+      <div class="btnclass" v-if="form.status !== 4">
+        <template v-if="form.status!==2">
+          <el-button @click="save(1)">保存</el-button>
+          <el-button type="primary" @click="save(2)">提交</el-button>
+        </template>
+        <template v-else>
+          <template v-if="$role=='sys_admin'||$role=='sys_high'">
+            <el-button @click="dialogFormVisible = true">审核不通过</el-button>
+            <el-button type="primary" @click="()=>{reason='',examine(4)}">审核通过</el-button>
+          </template>
+        </template>
+      </div>
+    </div>
+
+    <el-dialog title="审核不通过" :visible.sync="dialogFormVisible">
+      <el-form :model="form">
+        <el-form-item
+          label="选择原因"
+          :rules="[
+          { required: true, message: '选择原因不能为空'},
+        ]"
+        >
+          <el-radio-group v-model="reason">
+            <el-radio :label="'信息内容待调整'">信息内容待调整</el-radio>
+            <el-radio :label="'标题需进行修改'">标题需进行修改</el-radio>
+            <el-radio :label="2">自定义</el-radio>
+          </el-radio-group>
+          <el-input
+            v-model="zidingyi"
+            v-if="reason===2"
+            type="textarea"
+            :autosize="{ minRows: 2, maxRows: 4}"
+          ></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+        <el-button type="primary" @click="examine(3)">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from "@/components/main-top";
+import Tinymce from "@/components/Tinymce/index.vue";
+
+import { changeState } from "@/util/commonfn.js";
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+    Tinymce
+  },
+  data() {
+    const crumbData = [
+      {
+        name: "特有精神信息",
+        id: 0,
+      },
+      {
+        name: this.$route.params.type ? "编辑特有精神" : "新增特有精神",
+        id: 1,
+      },
+    ];
+
+    return {
+      crumbData,
+      reason: "信息内容待调整",
+      zidingyi: "",
+      dialogFormVisible: false,
+      form: {
+        content: "",
+        display: false,
+        author:"",
+        id: "",
+        img: "",
+        thumb: "",
+        title: "",
+        unit: "",
+      },
+      display: true,
+      type: this.$route.params.type,
+      id: this.$route.params.id,
+      token: window.localStorage.getItem("token"),
+      uploadUrl: `${this.$serverName}manage/file/upload`,
+      rules: {
+        title: [{ required: true, message: "请输入标题", trigger: "blur" }],
+        author: [{ required: true, message: "请输入作者", trigger: "blur" }],
+        unit: [{ required: true, message: "请输入归属单位", trigger: "blur" }],
+        img: [{ required: true, message: "请上传封面图片", trigger: "blur" }],
+      },
+    };
+  },
+  methods: {
+    handleBlur(data){
+      this.form.content = data
+    },
+    back() {
+      if(this.form.status===2){
+          this.$router.back();
+      }
+      else{
+        this.$confirm("点击返回后, 编辑的信息将无法保存,是否继续?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }).then(() => {
+          this.$router.back();
+        });
+      }
+    },
+    changeState(item) {
+      changeState(item, "spirit");
+    },
+    handleError(){
+      this.$alert("上传失败,请稍后再试", "提示", {
+        confirmButtonText: "确定",
+        callback: () => {
+          this.loading.close()
+        },
+      });
+    },
+    handleThumbSuccess(res) {
+      this.loading.close();
+      let { data } = res;
+      this.form.thumb = data.thumb;
+      this.form.img = data.urlPath;
+    },
+    beforeAvatarUpload(file) {
+      let type = this.isImage(file.name);
+      if (!type) {
+        this.$message.error("只允许上传图片");
+        return type;
+      }
+      const isLt2M = file.size / 1024 / 1024 < 20;
+
+      if (!isLt2M) {
+        this.$message.error("上传头像图片大小不能超过 20MB!");
+        return isLt2M;
+      }
+      this.loading = this.$loading(this.loadOption);
+    },
+
+    async examine(status) {
+      this.$confirm("请再次确认是否进行此审核操作?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(async () => {
+          let result = await this.$http({
+            method: "post",
+            data: {
+              id: this.form.id,
+              reason: this.reason === 2 ? this.zidingyi : this.reason,
+              status,
+            },
+            headers: {
+              token: window.localStorage.getItem("token"),
+            },
+            url: `/manage/spirit/audit`,
+          });
+
+          if (result.code === 0) {
+            this.$alert("审核成功", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+                this.$router.back();
+              },
+            });
+          } else {
+            this.$notify.error({
+              title: "错误",
+              message: result.msg,
+            });
+          }
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消",
+          });
+        });
+    },
+
+    async postStatus(status){
+          let {
+            id = "",
+            content,
+            display,
+            img,
+            thumb,
+            title,
+            author,
+            unit,
+          } = this.form;
+          let params = {
+            id,
+            content,
+            unit,
+            display: display * 1,
+            img,
+            author,
+            thumb,
+            title,
+            status,
+          };
+          let result = await this.$http({
+            method: "post",
+            data: params,
+            headers: {
+              token: window.localStorage.getItem("token"),
+            },
+            url: `/manage/spirit/save`,
+          });
+
+          if (result.code === 0) {
+            this.$alert("操作成功", "提示", {
+              confirmButtonText: "确定",
+              callback: () => {
+                this.$router.back();
+              },
+            });
+          } else {
+            this.$notify.error({
+              title: "错误",
+              message: result.msg,
+            });
+          }
+    },
+
+    save(status) {
+      this.$refs["partform"].validate(async (valid) => {
+        if (valid) {
+          if(status == 2){
+             this.$confirm("请再次确认是否进行此审核操作?", "提示", {
+                confirmButtonText: "确定",
+                cancelButtonText: "取消",
+                type: "warning",
+              }).then(async () => {
+                  this.postStatus(status)
+                  })
+                .catch(() => {
+                  this.$message({
+                    type: "info",
+                    message: "已取消",
+                  });
+                });
+          }
+          else{
+            this.postStatus(status)
+          }      
+        }
+      });
+    },
+    async getDetail() {
+      let result = await this.$http({
+        method: "get",
+        headers: {
+          token: window.localStorage.getItem("token"),
+        },
+        url: `/manage/spirit/detail/${this.id}`,
+      });
+
+      this.form = result.data;
+      this.display = Boolean(this.form.display);
+      this.form["display"] = Boolean(this.form["display"]);
+    },
+  },
+  mounted() {
+    if (this.id && this.id !== "none") {
+      this.getDetail();
+    }
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.edit-body {
+  background: #fff;
+  height: 100%;
+  .edit-arch {
+    overflow-y: auto;
+    overflow-x: hidden;
+    height: calc(100% - 8.5rem - 20px);
+    background-color: #fff;
+    padding: 20px 40px 20px 20px;
+  }
+  .btnclass {
+    text-align: center;
+    border: 1px solid #ccc;
+    padding: 10px 0;
+    width: calc(100% - 80px);
+    margin: 0 auto;
+  }
+}
+</style>
+<style>
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  /* height: 178px; */
+  display: block;
+}
+</style>

+ 261 - 0
src/pages/exhibition/exhibitionEdit.vue

@@ -0,0 +1,261 @@
+<template>
+  <div class="Root">
+    <el-form
+      :model="form"
+      :rules="rules"
+      ref="form"
+      label-width="100px"
+      class="demo-ruleForm"
+    >
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="标题:" prop="name" maxlength="30">
+            <el-input v-model="form.name"></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="展览时间:" prop="startTime">
+            <el-date-picker
+              format="yyyy-MM-dd HH:mm"
+              value-format="yyyy-MM-dd HH:mm"
+              placeholder="选择开始时间"
+              type="datetime"
+              v-model="form.startTime"
+              style="width: 100%"
+            >
+            </el-date-picker>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item prop="endTime">
+            <el-date-picker
+              format="yyyy-MM-dd HH:mm"
+              value-format="yyyy-MM-dd HH:mm"
+              placeholder="选择开始时间"
+              type="datetime"
+              v-model="form.endTime"
+              style="width: 100%"
+            ></el-date-picker>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="图片:">
+            <el-upload
+              class="avatar-uploader"
+              ref="upload"
+              accept=".jpg,.png"
+              :headers="headerObj"
+              :action="uploadUrl"
+              :on-error="handleError"
+              :show-file-list="false"
+              :on-success="handleIconSuccess"
+              :before-upload="beforeIconUpload"
+              :on-change="handleChange"
+              :on-remove="handleRemove"
+            >
+              <img
+                v-if="form.thumb"
+                :src="OSSURL + form.thumb"
+                class="avatar"
+              />
+              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              <!-- 单纯用来刷新视图的变化的 -->
+              <el-input v-show="false" v-model="refresh"></el-input>
+            </el-upload>
+            <div>
+              <p style="color: #999">格式要求:</p>
+              <p style="color: #999; line-height: 1">
+                1、支持png,jpeg的图片格式
+              </p>
+              <p style="color: #999">2、最大可支持10M</p>
+            </div>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+
+
+      <el-row style="margin-bottom: 100px">
+        <el-col :span="24">
+          <el-form-item label="内容" prop="content" maxlength="30">
+            <vue-editor class="quill-editor" v-model="form.content" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="24">
+          <el-form-item>
+            <el-button type="primary" @click="submitForm('form')"
+              >保存</el-button>
+            <el-button @click="quxiao()">取消</el-button>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import * as common from "@/util/commonfn.js";
+import { VueEditor } from "vue2-editor";
+export default {
+  components: {
+    VueEditor,
+  },
+  data() {
+    return {
+      refresh: "未刷新",
+      headerObj: {
+        token: window.localStorage.getItem("token"),
+      },
+      form: {
+        name: "",
+        content: "",
+        startTime: "",
+        endTime: "",
+        fileIds: "",
+      },
+      rules: {
+        name: [{ required: true, message: "请输入标题", trigger: "blur" }],
+        startTime: [
+          { required: true, message: "请输入开始时间", trigger: "blur" },
+        ],
+        endTime: [
+          { required: true, message: "请输入结束时间", trigger: "blur" },
+        ],
+        content: [{ required: true, message: "请输入内容", trigger: "blur" }],
+      },
+      token: window.localStorage.getItem("token"),
+      uploadUrl: `${this.$serverName}manage/exhibition/upload`,
+      fileList: [],
+    };
+  },
+  props: {
+    layerid: {
+      //自动注入的layerid
+      type: String,
+      default: "",
+    },
+    iframeData: {
+      //传递的数据
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+  },
+  methods: {
+    quxiao(reload) {
+      this.$layer.close(this.layerid);
+      //点击取消 不刷新列表   点击确认 保存成功刷新列表
+      if (reload) {
+        this.$parent.getInformation();
+      }
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          if (!this["form"].thumb) {
+            common.tip("warning", "请上传图片");
+            return;
+          }
+          this.save();
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    async save() {
+      let { content, name, startTime, id, endTime,thumb} = this.form;
+      let data = {
+        content,
+        name,
+        startTime,
+        id,
+        endTime,
+        thumb
+      };
+      let result = await this.$http({
+        method: "post",
+        data,
+        url: `/manage/exhibition/save`,
+      });
+      if (result["code"] === 0) {
+        common.tip("success", "保存成功");
+        this.quxiao(true);
+      } else {
+        common.tip("error", "保存失败,请联系管理员");
+      }
+    },
+    handleError() {},
+    handleIconSuccess(res) {
+      let { data } = res;
+      this.form.thumb = data.ossPath;
+      // 刷新下页面
+      this.refresh = "刷新了";
+    },
+    beforeIconUpload(file) {
+      let size = 10;
+      const isLt = file.size / 1024 / 1024 < size;
+      if (!isLt) {
+        this.$message.error(`上传头像图片大小不能超过 ${size}MB!`);
+        return isLt;
+      }
+    },
+    handleChange(file) {
+      this.fileList = this.fileList.length === 0 ? this.fileList : [];
+      this.fileList.push(file["raw"]);
+    },
+    handleRemove(file) {
+      let index = this.fileList.findIndex((item) => {
+        return item.uid === file.uid;
+      });
+      this.fileList.splice(index, 1);
+    },
+  },
+  watch: {
+    iframeData: {
+      handler: function () {
+        this.form = this.iframeData;
+      },
+      deep: true,
+      immediate: true,
+    },
+  },
+  created() {},
+};
+</script>
+
+<style lang="less" scoped>
+.Root {
+  width: 100%;
+  padding: 50px;
+}
+
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+  border: 1px dashed #d9d9d9;
+}
+</style>
+

+ 229 - 0
src/pages/exhibition/exhibitionList.vue

@@ -0,0 +1,229 @@
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span>关键字:</span>
+            <el-input
+              class="elInput"
+              v-model="params.searchKey"
+              placeholder="请输入关键字"
+            ></el-input>
+
+            <el-button
+              style="margin-left: 1.25rem"
+              type="primary"
+              @click="getInformation(true)"
+              >查询</el-button
+            >
+            <el-button type="primary" @click="edit({}, 'add')">新增</el-button>
+          </div>
+          <div class="info-right"></div>
+        </div>
+        <el-table
+          :data="tableData"
+          height="61vh"
+          class="collection-con"
+          :tree-props="{ children: 'children' }"
+          row-key="id"
+          style="width: 100%"
+        >
+          <el-table-column
+            type="index"
+            label="序号"
+            :index="indexMethod"
+          ></el-table-column>
+          <el-table-column prop="name" label="展览标题"></el-table-column>
+          <el-table-column prop="userName" label="发布用户"></el-table-column>
+          <el-table-column prop="startTime" label="展览时间"></el-table-column>
+          <el-table-column prop="createTime" label="发布时间"></el-table-column>
+
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span
+                class="o-span"
+                v-if="$role == 'sys_admin' || $role == 'sys_high'"
+                @click="edit(scope.row, 'edit')"
+                >编辑</span
+              >
+              <span
+                class="o-span"
+                v-if="
+                  scope.row.isIndex != '1' &&
+                  ($role == 'sys_admin' || $role == 'sys_high')
+                "
+                @click="del(scope.row)"
+                >删除</span
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="params.pageNum"
+            @size-change="handleSizeChange"
+            :page-size="params.pageSize"
+            :page-sizes="[10, 20, 50]"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from "@/components/main-top";
+import exhibitionEdit from "@/pages/exhibition/exhibitionEdit";
+
+const crumbData = [
+  {
+    name: "展览资讯",
+    id: 3 - 1,
+  },
+];
+
+export default {
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      crumbData,
+      tableData: [],
+      params: {
+        pageNum: 1,
+        pageSize: 10,
+        searchKey: ""
+      },
+      total: 0,
+      token: window.localStorage.getItem("token")
+    };
+  },
+  computed: {},
+  watch: {},
+  created() {
+    this.getInformation();
+  },
+  mounted() {},
+
+  methods: {
+    indexMethod(index) {
+      return (this.params.pageNum - 1) * this.params.pageSize + index + 1;
+    },
+    edit(item = {}, type) {
+      this.$layer.iframe({
+        content: {
+          content: exhibitionEdit,
+          parent: this,
+          data: { iframeData: item,type},
+        },
+        area: ["900px", "600px"],
+        title: `${type === "add" ? "新增" : "编辑"}展览资讯`,
+        maxmin: false,
+        shade: false,
+        shadeClose: false,
+        cancel: () => {
+          //关闭弹窗事件
+          this.getInformation()
+        },
+      });
+    },
+    del(item) {
+      this.$confirm("是否确认删除这个展览?", "提示", {
+        confirmButtonText: "是",
+        cancelButtonText: "否",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http
+            .get(`/manage/exhibition/remove/${item.id}`, {})
+            .then((res) => 
+            
+            {
+              if (res.code === 0) {
+                this.$alert("删除成功", "提示", {
+                  confirmButtonText: "确定",
+                  callback: () => {
+                    this.getInformation();
+                  },
+                });
+              } else {
+                this.$notify.error({
+                  title: "错误",
+                  message: res.msg,
+                });
+              }
+            });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    handleCurrentChange(val) {
+      this.params.pageNum = val;
+      this.getInformation();
+    },
+    handleSizeChange(val) {
+      this.params.pageSize = val;
+      this.getInformation();
+    },
+    async getInformation(reload = false) {
+      if (reload) {
+        this.params.pageNum = 1;
+        this.tableData = [];
+      }
+      let result = await this.$http({
+        method: "post",
+        data: this.params,
+        url: "/manage/exhibition/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.tableData = result.data.list;
+      this.tableData = this.tableData.map(item=>{
+        return {...item,startTime:item.startTime && item.startTime.slice(0,-3)}
+      })
+      this.total = result.data.total;
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow: auto;
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+</style>
+

+ 124 - 0
src/pages/exhibition/exhibitionOnline.vue

@@ -0,0 +1,124 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body" style="padding: 50px 20px">
+        <el-form
+          :model="form"
+          :rules="rules"
+          ref="form"
+          label-width="100px"
+          class="demo-ruleForm"
+        >
+          <el-form-item label="链接地址:" prop="url">
+            <el-input
+              v-model="form.url"
+              style="width: 46%"
+              placeholder="请输入链接地址"
+            ></el-input>
+          </el-form-item>
+
+          <el-form-item>
+            <el-button type="primary" @click="submitForm('form')"
+              >保存</el-button
+            >
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+const crumbData = [
+  {
+    name: "线上展览",
+    id: 3,
+  },
+];
+import MainTop from "@/components/main-top";
+import * as common from "@/util/commonfn.js";
+export default {
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      crumbData,
+      form: {},
+      rules: {
+        url: [{ required: true, message: "请输入地址", trigger: "blur" }],
+      },
+      token: window.localStorage.getItem("token"),
+    };
+  },
+  computed: {},
+  watch: {},
+  mounted() {},
+  created() {
+      this.getDetail()
+  },
+  methods: {
+    async getDetail() {
+      let result = await this.$http({
+        method: "get",
+        url: "/manage/onlineExhibition/detail/1",
+      });
+      if(result['code'] === 0){
+        this["form"] = result['data'];
+      } else {
+        this["form"] = {}
+      }
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.save();
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    async save() {
+      let data ={url:this["form"].url,id:this["form"].id} ;
+      let result = await this.$http({
+        method: "get",
+        params:data,
+        url: `/manage/onlineExhibition/save/${data.id}`
+      });
+      if(result['code'] === 0) {
+          common.tip('success','保存成功');
+          this.getDetail()
+      } else {
+        common.tip('error','保存失败,请联系管理员');
+      }
+    }
+  }
+};
+</script>
+
+<style scoped>
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow: auto;
+}
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+.info-top {
+  padding: 20px 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px #a5a5a5 solid;
+}
+</style>

+ 267 - 0
src/pages/home/rotation.vue

@@ -0,0 +1,267 @@
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body" style="padding: 50px 20px">
+        <h1 class="pic">图片:</h1>
+        <ul>
+          <li v-for="(item,index) in dataList" :key="index" @click="edit(item, 'edit')">
+            <img :src="OSSURL +item.ossPath" alt="" />
+            <div class="del" @click.stop="del(item)">
+              <img :src="require(`@/assets/img/del.png`)" alt="" >
+            </div>
+
+            <div class="my-move">
+              <div class="pre" @click.stop="switchPic('pre',item)" >上一张</div>
+              <div class="next" @click.stop="switchPic('next',item)">下一张</div>
+            </div>
+          </li>
+          <li v-if="dataList.length < 5" @click="edit({}, 'add')">
+            <img :src="require(`@/assets/img/plus.png`)" alt="" />
+            <!-- 占位 -->
+            <div class="my-move">
+            </div>
+          </li>
+        </ul>
+        <div class="desc">
+          <p>
+            格式要求:支持png、jpg、gif和jpeg的图片格式,<br>
+            单张最大支持20M,建议尺寸1920*1080<br>
+            数量:最多可上传5张图片。
+          </p>
+          
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+const crumbData = [
+  {
+    name: "轮播图片",
+    id: 1,
+  },
+];
+import MainTop from "@/components/main-top";
+import rotationEdit from "@/pages/home/rotationEdit.vue";
+import * as common from "@/util/commonfn.js";
+export default {
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      crumbData,
+      dataList: [],
+    };
+  },
+  computed: {},
+  watch: {},
+  mounted() {},
+  created() {
+    this.getList();
+  },
+  methods: {
+    async getList(reload = false) {
+      if (reload) {
+        this.params.pageNum = 1;
+        this.dataList = [];
+      }
+      let result = await this.$http({
+        method: "post",
+        data: this.params,
+        url: "/manage/slideshow/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.dataList = result.data;
+      this.total = this.dataList.total;
+    },
+    edit(item = {}, type) {
+      console.log("item", item);
+      this.$layer.iframe({
+        content: {
+          content: rotationEdit,
+          parent: this,
+          data: { iframeData: item,type:type },
+        },
+        area: ["900px", "600px"],
+        title: `${type === "add" ? "新增" : "编辑"}轮播图片`,
+        maxmin: false,
+        shade: false,
+        shadeClose: false,
+        cancel: () => {
+          //关闭弹窗事件
+        },
+        
+      });
+    },
+    del(item) {
+      console.log("item", item);
+      this.$confirm("是否确认删除这个图片?", "提示", {
+        confirmButtonText: "是",
+        cancelButtonText: "否",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http
+            .get(`/manage/slideshow/remove/${item.id}`, {})
+            .then((res) => {
+              if (res.code === 0) {
+                this.$alert("删除成功", "提示", {
+                  confirmButtonText: "确定",
+                  callback: () => {
+                    this.getList();
+                  },
+                });
+              } else {
+                this.$notify.error({
+                  title: "错误",
+                  message: res.msg,
+                });
+              }
+            });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    switchPic(type,item){
+      let len = this.dataList.length;
+      if(len === 1) {
+        type === 'pre'? common.tip("warning", "已是第一张"): common.tip("warning", "已是最后一张")
+        return;
+      }
+      let currentItem = item;
+      let preCurrentItem = {};
+      let nextCurrentItem = {};
+      if(currentItem.sort === 1) {
+          preCurrentItem = this.dataList[this.dataList.length-1];
+          nextCurrentItem = this.dataList.filter(e=>e.sort === currentItem.sort+1)[0];
+      }
+      else if(currentItem.sort === this.dataList.length) {
+          preCurrentItem = this.dataList.filter(e=>e.sort === currentItem.sort-1)[0];
+          nextCurrentItem = this.dataList[0];
+      } else {
+        preCurrentItem = this.dataList.filter(e=>e.sort === currentItem.sort-1)[0] ;
+        nextCurrentItem = this.dataList.filter(e=>e.sort === currentItem.sort+1)[0];
+      }
+      if(type === 'pre') {
+        [preCurrentItem.sort,currentItem.sort] = [currentItem.sort,preCurrentItem.sort]
+      }
+      if(type === 'next') {
+        [nextCurrentItem.sort,currentItem.sort] = [currentItem.sort,nextCurrentItem.sort]
+      }
+      Promise.all([this.changeOrder(currentItem),this.changeOrder(type === 'pre'?preCurrentItem:nextCurrentItem)]).then(([res1,res2]) =>{
+        if(res1.code === 0 && res2.code === 0) {
+          common.tip("success","移动成功");
+          this.getList()
+        }
+        else {
+          common.tip("error", "移动成功,请联系管理员");
+        }
+      })
+    },
+    changeOrder(item) {
+      let data = {...item};
+      return this.$http({
+        method: "post",
+        data,
+        url: `/manage/slideshow/save`,
+      });
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow-y: auto;
+}
+.top-body {
+  width: 100%;
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+  .pic {
+    font-size: 18px;
+    margin-bottom: 20px;
+  }
+  .desc {
+    margin: 30px 0;
+  }
+}
+.info-top {
+  padding: 20px 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px #a5a5a5 solid;
+}
+.top-body {
+  ul {
+    width: 100%;
+    li {
+      display: inline-block;
+      border: 10px solid gray;
+      width: 200px;
+      height: 200px;
+      margin-right: 20px;
+      margin-bottom: 20px;
+      padding: 1px;
+      box-sizing: border-box;
+      cursor: pointer;
+      position: relative;
+      .del {
+        width: 30px;
+        height: 30px;
+        position: absolute;
+        top: 0;
+        right: 0;
+        background: red;
+        >img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+      > img {
+        width: 100%;
+        height: 100%;
+      }
+      .my-move {
+        width: 100%;
+        height: 40px;
+        margin-top: 10px;
+        display: inline-block;
+        .pre {
+          width: 45%;
+          line-height: 40px;
+          text-align: center;
+          background: dodgerblue;
+          cursor: pointer;
+          float: left;
+        }
+        .next {
+          width: 45%;
+          line-height: 40px;
+          text-align: center;
+          background: dodgerblue;
+          cursor: pointer;
+          float: right;
+        }
+      }
+    }
+  }
+}
+</style>

+ 226 - 0
src/pages/home/rotationEdit.vue

@@ -0,0 +1,226 @@
+<template>
+  <div class="Root">
+    <el-form
+      :model="ruleForm"
+      :rules="rules"
+      ref="ruleForm"
+      label-width="100px"
+      class="demo-ruleForm"
+    >
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="链接:" prop="url">
+            <el-input v-model="ruleForm.url"></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="轮播图片:">
+            <el-upload
+              class="avatar-uploader"
+              ref="upload"
+              accept=".jpg,.png"
+              :headers="headerObj"
+              :action="uploadUrl"
+              :on-error="handleError"
+              :show-file-list="false"
+              :on-success="handleIconSuccess"
+              :before-upload="beforeIconUpload"
+              :on-change="handleChange"
+              :on-remove="handleRemove"
+            >
+              <img
+                v-if="ruleForm.ossPath"
+                :src="OSSURL + ruleForm.ossPath"
+                class="avatar"
+              />
+              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              <!-- 单纯用来刷新视图的变化的 -->
+              <el-input v-show="false" v-model="refresh"></el-input>
+            </el-upload>
+            <div>
+              <p style="color: #999">格式要求:</p>
+              <p style="color: #999; line-height: 1">
+                1、支持png,jpeg的图片格式
+              </p>
+              <p style="color: #999">2、最大可支持10M</p>
+            </div>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-form-item>
+          <el-button type="primary" @click="submitForm('ruleForm')"
+            >保存</el-button
+          >
+          <el-button @click="quxiao()">取消</el-button>
+        </el-form-item>
+      </el-row>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import * as common from "@/util/commonfn.js";
+export default {
+  components: {},
+  data() {
+    return {
+      refresh: "未刷新",
+      headerObj: {
+        token: window.localStorage.getItem("token"),
+      },
+      ruleForm: {
+        url: "",
+        fileName:"",
+        ossPath:""
+      },
+      rules: {
+        url: [{ required: true, message: "请输入链接", trigger: "blur" }],
+        // pic: [{ required: true, message: "请上传轮播图片", trigger: "blur" }],
+      },
+      token: window.localStorage.getItem("token"),
+      uploadUrl: `${this.$serverName}manage/slideshow/upload`,
+      fileList: [],
+    };
+  },
+  props: {
+    layerid: {
+      //自动注入的layerid
+      type: String,
+      default: "",
+    },
+    iframeData: {
+      //传递的数据
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+    type: {
+      //传递的数据
+      type: String,
+      default: () => {
+        return '';
+      },
+    },
+  },
+  methods: {
+    quxiao(reload) {
+      this.$layer.close(this.layerid);
+      //点击取消 不刷新列表   点击确认 保存成功刷新列表
+      if (reload) {
+        this.$parent.getList();
+      }
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          if (!this["ruleForm"].ossPath) {
+            common.tip("warning", "请上传图片");
+            return;
+          }
+          this.save();
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    async save() {
+      let {
+        fileName,
+        id='',
+        ossPath,
+        url
+      } = this.ruleForm;
+      let data = {
+        fileName,
+        id,
+        ossPath,
+        url
+      };
+      if(this.type === "add"){
+        data = {...data,sort:this.$parent.dataList.length + 1}
+      }
+      let result = await this.$http({
+        method: "post",
+        data,
+        url: `/manage/slideshow/save`,
+      });
+      if (result["code"] === 0) {
+        common.tip("success", "保存成功");
+        this.quxiao(true);
+      } else {
+        common.tip("error", "保存失败,请联系管理员");
+      }
+    },
+    handleError() {},
+    handleIconSuccess(res) {
+      let { data } = res;
+      this.ruleForm.ossPath = data.ossPath;
+      this.ruleForm.fileName = data.fileName
+      // 刷新下页面
+      this.refresh = "刷新了";
+    },
+    beforeIconUpload(file) {
+      let size = 10;
+      const isLt = file.size / 1024 / 1024 < size;
+      if (!isLt) {
+        this.$message.error(`上传头像图片大小不能超过 ${size}MB!`);
+        return isLt;
+      }
+    },
+    handleChange(file) {
+      this.fileList = this.fileList.length === 0 ? this.fileList : [];
+      this.fileList.push(file["raw"]);
+    },
+    handleRemove(file) {
+      let index = this.fileList.findIndex((item) => {
+        return item.uid === file.uid;
+      });
+      this.fileList.splice(index, 1);
+    },
+  },
+  watch: {
+    iframeData: {
+      handler: function () {
+        this.ruleForm = this.iframeData;
+      },
+      deep: true,
+      immediate: true,
+    },
+  },
+  created() {},
+};
+</script>
+
+<style lang="less" scoped>
+.Root {
+  width: 100%;
+  padding: 50px;
+}
+
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+  border: 1px dashed #d9d9d9;
+}
+</style>
+

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

@@ -0,0 +1,244 @@
+<!-- default-active="1-1"  -->
+<template>
+  <div class="aside">
+    <div class="aside-list">
+      <el-row class="tac">
+        <el-col :span="24">
+          <el-menu
+            :default-active="$route.path"
+            router
+            class="el-menu-vertical-demo"
+            @open="handleOpen"
+            @close="handleClose"
+          >
+            <el-submenu index="1">
+              <template slot="title">
+                <i class="el-icon-s-home"></i>
+                <span>首页信息</span>
+              </template>
+              <el-menu-item-group>
+                <el-menu-item index="/rotation">轮播图片</el-menu-item>
+                <!-- <el-menu-item index="/openTime">开放时间</el-menu-item>
+                <el-menu-item index="/reservationService"
+                  >预约服务</el-menu-item
+                >
+                <el-menu-item index="/trafficRoutes">交通路线</el-menu-item> -->
+              </el-menu-item-group>
+            </el-submenu>
+
+            <el-submenu index="8">
+              <template slot="title">
+                <i class="el-icon-eleme"></i>
+                <span>概况</span>
+              </template>
+              <el-menu-item-group>
+                <el-menu-item index="/survey">概况信息</el-menu-item>
+              </el-menu-item-group>
+            </el-submenu>
+
+            <el-submenu index="2">
+              <template slot="title">
+                <i class="el-icon-news"></i>
+                <span>资讯</span>
+              </template>
+              <el-menu-item-group>
+                <el-menu-item index="/newsList">资讯内容</el-menu-item>
+                <el-menu-item index="/bookList">书籍</el-menu-item>
+              </el-menu-item-group>
+            </el-submenu>
+            <el-submenu index="3">
+              <template slot="title">
+                <i class="el-icon-coin"></i>
+                <span>展览大全</span>
+              </template>
+              <el-menu-item-group>
+                <el-menu-item index="/exhibitionOnline">线上展览</el-menu-item>
+              </el-menu-item-group>
+              <el-menu-item-group>
+                <el-menu-item index="/exhibition">展览资讯</el-menu-item>
+              </el-menu-item-group>
+            </el-submenu>
+            <el-submenu index="4">
+              <template slot="title">
+                <i class="el-icon-s-shop"></i>
+                <span>藏品信息</span>
+              </template>
+              <el-menu-item-group>
+                <el-menu-item index="/collectionSort">藏品分类</el-menu-item>
+                <el-menu-item index="/collectionYear">藏品年代</el-menu-item>
+                <el-menu-item index="/collection">藏品信息</el-menu-item>
+              </el-menu-item-group>
+            </el-submenu>
+            <el-submenu index="5">
+              <template slot="title">
+                <i class="el-icon-user-solid"></i>
+                <span>活动资讯</span>
+              </template>
+              <el-menu-item-group>
+                <el-menu-item index="/activity">活动资讯</el-menu-item>
+              </el-menu-item-group>
+              <el-menu-item-group>
+                <el-menu-item index="/questionnaire">问卷调查</el-menu-item>
+              </el-menu-item-group>
+            </el-submenu>
+            <el-submenu index="6" v-if="$role == 'sys_admin'">
+              <template slot="title">
+                <i class="el-icon-s-comment"></i>
+                <span>留言板</span>
+              </template>
+              <el-menu-item-group>
+                <el-menu-item index="/leaveMessage">留言管理</el-menu-item>
+              </el-menu-item-group>
+              <el-menu-item-group>
+                <el-menu-item index="/guide">参观指南</el-menu-item>
+              </el-menu-item-group>
+            </el-submenu>
+            <el-submenu index="7" v-if="$role == 'sys_admin'">
+              <template slot="title">
+                <i class="el-icon-location"></i>
+                <span>系统管理</span>
+              </template>
+              <el-menu-item-group>
+                <el-menu-item index="/user">用户管理</el-menu-item>
+                <el-menu-item index="/worklog">日志管理</el-menu-item>
+                <el-menu-item index="/analysis">统计分析</el-menu-item>
+                <!-- <el-menu-item index="/password">密码修改</el-menu-item> -->
+              </el-menu-item-group>
+            </el-submenu>
+          </el-menu>
+        </el-col>
+      </el-row>
+      <!-- <div class="aside-item">
+        <div :class="{ active: activeIdx >= 7 && activeIdx <= 11 }">
+          <i class="iconfont iconsys_nav_system"></i>系统管理
+        </div>
+        <template v-if="$role == 'sys_admin'">
+          <div @click="go(9, '/user')" :class="{ activeFont: activeIdx === 9 }">
+            账号管理
+          </div>
+          <div
+            @click="go(10, '/worklog')"
+            :class="{ activeFont: activeIdx === 10 }"
+          >
+            日志管理
+          </div>
+        </template>
+        <div
+          @click="go(11, '/password')"
+          :class="{ activeFont: activeIdx === 11 }"
+        >
+          密码修改
+        </div>
+      </div> -->
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {},
+  data() {
+    // 这里存放数据
+    return {
+      // activeIdx: 0
+    };
+  },
+  // 监听属性 类似于data概念
+  computed: {
+    // activeIdx: {
+    //   get: function () {
+    //     return this.$route.meta.index;
+    //   },
+    //   set: function () {},
+    // },
+  },
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+    // go(id, url) {
+    //   this.activeIdx = this.$route.meta.index;
+    //   this.$router.push(url);
+    // },
+    handleOpen() {},
+    handleClose() {},
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    // console.log("this", this);
+    // console.log("this.$route", this.$route);
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+};
+</script>
+
+<style scoped>
+.aside-list {
+  width: 100%;
+  padding-top: 1.5rem;
+}
+.aside-item {
+  padding: 0.625rem 0;
+  text-align: center;
+}
+
+.aside-item:last-child {
+  border-bottom: none;
+}
+
+.aside-item div {
+  height: 2.875rem;
+  line-height: 2.875rem;
+  margin: 0.0625rem 0;
+  width: 89%;
+  padding-left: 5.7rem;
+  font-size: 0.875rem;
+  cursor: pointer;
+  color: #707070;
+  text-align: left;
+}
+.aside-item div:not(:first-child):hover {
+  color: #b63c25;
+}
+
+.aside-item div:first-child {
+  padding-left: 3.81rem;
+  display: flex;
+  align-items: center;
+  color: #532f1c;
+  font-size: 1.25rem;
+  font-weight: bold;
+  margin-bottom: 0.2rem;
+}
+
+.aside-item div:first-child img {
+  width: 1.1rem;
+  height: 1.1rem;
+  margin-right: 0.625rem;
+}
+
+.aside-item .iconfont {
+  color: #532f1c;
+  margin-right: 0.8125rem;
+}
+
+.aside-item .active {
+  background-color: #b63c25;
+  border-top-right-radius: 80px;
+  border-bottom-right-radius: 80px;
+  color: #f2ecde !important;
+}
+
+.aside-item .active .iconfont {
+  color: #f2ecde;
+}
+
+.aside-item .activeFont {
+  color: #b63c25;
+}
+</style>

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

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

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

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

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

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

+ 130 - 0
src/pages/leaveMessage/guide.vue

@@ -0,0 +1,130 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body" style="padding: 50px 20px">
+        <el-form
+          :model="form"
+          :rules="rules"
+          ref="form"
+          label-width="100px"
+          class="demo-ruleForm"
+        >
+        <el-row>
+        <el-col :span="24">
+          <el-form-item label="内容" prop="content">
+            <vue-editor class="quill-editor" v-model="form.content" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+          <el-form-item>
+            <el-button type="primary" @click="submitForm('form')"
+              >保存</el-button
+            >
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+const crumbData = [
+  {
+    name: "参观指南",
+    id: 3,
+  },
+];
+import MainTop from "@/components/main-top";
+import * as common from "@/util/commonfn.js";
+import { VueEditor} from "vue2-editor";
+export default {
+  components: {
+    MainTop,
+    VueEditor
+  },
+  data() {
+    return {
+      crumbData,
+      form: {},
+      rules: {
+        content: [{ required: true, message: "请输入内容", trigger: "blur" }],
+      },
+      token: window.localStorage.getItem("token"),
+    };
+  },
+  computed: {},
+  watch: {},
+  mounted() {},
+  created() {
+      this.getDetail()
+  },
+  methods: {
+    async getDetail() {
+      let result = await this.$http({
+        method: "get",
+        url: "/manage/guide/detail/4",
+      });
+      if(result['code'] === 0){
+        this["form"] = result['data'];
+      } else {
+        this["form"] = {}
+      }
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.save();
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    async save() {
+      let data = this["form"];
+      let result = await this.$http({
+        method: "post",
+        data,
+        url: "/manage/guide/save"
+      });
+      if(result['code'] === 0) {
+          common.tip('success','保存成功');
+          this.getDetail()
+      } else {
+        common.tip('error','保存失败,请联系管理员');
+      }
+    }
+  }
+};
+</script>
+
+<style scoped>
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow: auto;
+}
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+.info-top {
+  padding: 20px 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px #a5a5a5 solid;
+}
+</style>
+
+<style>
+
+.ck-content { height:500px; }
+</style>

+ 244 - 0
src/pages/leaveMessage/leaveMessageList.vue

@@ -0,0 +1,244 @@
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span style="margin-left: 1.25rem">时间范围:</span>
+            <el-date-picker
+              v-model="params.startTime"
+              format="yyyy-MM-dd"
+              value-format="yyyy-MM-dd"
+              placeholder="选择开始时间"
+            >
+            </el-date-picker>
+            -
+            <el-date-picker
+              v-model="params.endTime"
+              format="yyyy-MM-dd"
+              value-format="yyyy-MM-dd"
+              placeholder="选择结束时间"
+            >
+            </el-date-picker>
+            &nbsp;
+            <span>关键字:</span>
+            <el-input
+              class="elInput"
+              v-model="params.searchKey"
+              placeholder="请输入关键字"
+            ></el-input>
+
+            <el-button
+              style="margin-left: 1.25rem"
+              type="primary"
+              @click="getInformation(true)"
+              >查询</el-button
+            >
+            <!-- <el-button type="primary" @click="edit({}, 'add')">新增</el-button> -->
+          </div>
+          <div class="info-right"></div>
+        </div>
+        <el-table
+          :data="tableData"
+          height="61vh"
+          class="collection-con"
+          :tree-props="{ children: 'children' }"
+          row-key="id"
+          style="width: 100%"
+        >
+          <el-table-column
+            type="index"
+            label="序号"
+            :index="indexMethod"
+          ></el-table-column>
+          <el-table-column prop="content" label="评论内容"></el-table-column>
+          <el-table-column prop="nickName" label="用户昵称"></el-table-column>
+          <el-table-column prop="createTime" label="发布时间"></el-table-column>
+          <el-table-column label="显示">
+            <template slot-scope="scope">
+              <el-switch :active-value="1" :inactive-value="0"
+                v-model="scope.row.display"
+                @change="switchChange(scope.row)"
+              >
+              </el-switch>
+            </template>
+          </el-table-column>
+
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span
+                class="o-span"
+                @click="del(scope.row)"
+                >删除</span
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="params.pageNum"
+            @size-change="handleSizeChange"
+            :page-size="params.pageSize"
+            :page-sizes="[10, 20, 50]"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import MainTop from "@/components/main-top";
+import * as common from "@/util/commonfn.js";
+
+const crumbData = [
+  {
+    name: "留言管理",
+    id: 6 - 1,
+  },
+];
+
+export default {
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      crumbData,
+      tableData: [],
+      params: {
+        pageNum: 1,
+        pageSize: 10,
+        searchKey: "",
+        startTime:"",
+        endTime:""
+      },
+      total: 0,
+    };
+  },
+  computed: {},
+  watch: {},
+  created() {
+    this.getInformation();
+  },
+  mounted() {},
+
+  methods: {
+    indexMethod(index) {
+      return (this.params.pageNum - 1) * this.params.pageSize + index + 1;
+    },
+    del(item) {
+      this.$confirm("是否确认删除这条留言?", "提示", {
+        confirmButtonText: "是",
+        cancelButtonText: "否",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http.get(`/manage/comment/removes/${item.id}`, {}).then((res) => {
+            if (res.code === 0) {
+              this.$alert("删除成功", "提示", {
+                confirmButtonText: "确定",
+                callback: () => {
+                  this.getInformation();
+                },
+              });
+            } else {
+              this.$notify.error({
+                title: "错误",
+                message: res.msg,
+              });
+            }
+          });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    handleCurrentChange(val) {
+      this.params.pageNum = val;
+      this.getInformation();
+    },
+    handleSizeChange(val) {
+      this.params.pageSize = val;
+      this.getInformation();
+    },
+    async getInformation(reload = false) {
+      if (reload) {
+         if(!this.params.startTime && this.params.endTime){
+          common.tip('error','请选择开始时间')
+          return;
+        }
+        if(this.params.startTime && !this.params.endTime){
+          common.tip('error','请选择结束时间')
+          return;
+        }
+        this.params.pageNum = 1;
+        this.tableData = [];
+      }
+      this.params.startTime = this.params.startTime && `${this.params.startTime} 00:00:00` || ""
+      this.params.endTime = this.params.endTime && `${this.params.endTime} 23:59:59` || ""
+      let result = await this.$http({
+        method: "post",
+        data: this.params,
+        url: "/manage/comment/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.tableData = result.data.list.map((item) => {
+        return { ...item, switchFlag: item.isIndex ? true : false };
+      });
+      this.total = result.data.total;
+    },
+    switchChange(item) {
+      this.display(item);
+    },
+    async display(item = {}) {
+      let result = await this.$http({
+        method: "get",
+        url: `/manage/comment/display/${item.id}/${item.display}`,
+      });
+      if (result.code == 0) {
+        common.tip("success", "修改成功");
+        this.getInformation();
+      } else {
+        common.tip("error", "修改失败,请联系管理员");
+      }
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow: auto;
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+</style>
+

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

@@ -0,0 +1,227 @@
+<!--  -->
+<template>
+<div class='layout'>
+  <div class="layout-con">
+    <div class="logo">
+      <img :src="require('@/assets/img/logo.png')" alt="">
+      <span></span>
+    </div>
+    <img class="bg" :src="require('@/assets/img/bg.jpg')" alt="">
+    <div class="middle">
+      <div class="middle-left">
+        <div>大理博物馆管理后台</div>
+      </div>
+      <div class="middle-right">
+        <el-form class="middle-form" :rules="ruleLogin" status-icon :model="formLogin" ref="formLogin">
+          <div>欢迎登录</div>
+          <el-form-item prop="username">
+            <el-input v-model="formLogin.username" placeholder="账号"></el-input>
+          </el-form-item>
+          <el-form-item prop="password">
+            <el-input @keyup.enter.native="submitForm('formLogin')" v-model="formLogin.password" placeholder="密码" type="password"></el-input>
+          </el-form-item>
+          <el-form-item>
+            <el-button  @click="submitForm('formLogin')" type="primary" >登录</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+  </div>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import { encodeStr } from '@/util'
+import { Base64 } from 'js-base64'
+
+import Vue from 'vue'
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {},
+  data () {
+    var checkUsername = (rule, value, callback) => {
+      if (!value) {
+        return callback(new Error('账号不能为空'))
+      } else {
+        callback()
+      }
+    }
+    var validatePass = (rule, value, callback) => {
+      if (value === '') {
+        callback(new Error('请输入密码'))
+      } else {
+        callback()
+      }
+    }
+    // 这里存放数据
+    return {
+      formLogin: {
+        username: '',
+        password: '',
+        region: 'high'
+      },
+      ruleLogin: {
+        username: [
+          { validator: checkUsername, trigger: 'blur' }
+        ],
+        password: [
+          { validator: validatePass, trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {
+    userId () {
+      return window.localStorage.getItem('userInfo')
+    }
+  },
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+    submitForm (formName) {
+      this.$refs[formName].validate((valid) => {
+        console.log(encodeStr(Base64.encode(this.formLogin.password)));
+        let data = {
+          userName: this.formLogin.username,
+          password: this.formLogin.password,
+          from:'cms'
+        }
+        if (valid) {
+          this.$http.post('/admin/login', data).then(res => {
+            if (res.code === 0) {
+              window.localStorage.setItem('token', String(res.data.token))
+              window.localStorage.setItem('userInfo', JSON.stringify(res.data.user))
+              window.localStorage.setItem('role', res.data.user.role)
+              Vue.prototype.$role = res.data.user.role
+              this.$router.push('/')
+            } else {
+              this.$notify.error({
+                title: '错误',
+                message: res.msg
+              })
+            }
+          })
+        } else {
+          return false
+        }
+      })
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+    if (this.userId) {
+      this.$router.push({path:'/'})
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.layout{
+  .layout-con{
+     width: 100%;
+     position: relative;
+     .logo{
+       position: absolute;
+       left: 35px;
+       top: 100px;
+       z-index: 999;
+       cursor: pointer;
+       height: auto;
+       display: flex;
+        align-items: center;
+        img {
+          width: 30%;
+        }
+        span{
+          color: #fff;
+          font-size: 24px;
+          font-weight: bold;
+        }
+     }
+    .bg{
+      width: 100%;
+      height: 100%;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%,-50%);
+      z-index: 0;
+      position: fixed;
+      user-select: none;
+    }
+    .middle{
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      width: 800px;
+      min-height: 56vh;
+      position: absolute;
+      transform: translate(-50%,-50%);
+      left: 50%;
+      top: 50%;
+      .middle-left{
+        background: rgba(#9D362F, 0.7);
+        width: 50%;
+        height: 100%;
+        position: relative;
+        >div{
+          width: 100%;
+          text-align: center;
+          position: absolute;
+          top: 50%;
+          left: 50%;
+          transform: translate(-50%,-50%);
+          font-size: 32px;
+          text-shadow: 0 4px 6px rgba(0, 0, 0, 0.7);
+          color: #f2ecde;
+          line-height: 40px;
+        }
+        img{
+          position: absolute;
+          width: 100%;
+          left: 0;
+        }
+        .top{
+          top: 0;
+        }
+        .bottom{
+          bottom: 0;
+          transform: rotate(180deg);
+        }
+      }
+      .middle-right{
+        position: relative;
+        height: 100%;
+        background: rgba(#fff, 0.7);
+        width: 50%;
+        .middle-form{
+          width: 80%;
+          position: absolute;
+          top: 50%;
+          left: 50%;
+          transform: translate(-50%,-50%);
+          >div{
+            text-align: center;
+            margin-bottom: 50px;
+            font-size: 24px;
+          }
+        }
+      }
+    }
+  }
+}
+</style>
+
+<style scoped>
+.el-button--primary {
+  width: 100%;
+}
+</style>

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

@@ -0,0 +1,3 @@
+.el-button--primary {
+  width: 100%;
+}

+ 241 - 0
src/pages/news/bookEdit.vue

@@ -0,0 +1,241 @@
+<template>
+  <div class="Root">
+    <el-form
+      :model="ruleForm"
+      :rules="rules"
+      ref="ruleForm"
+      label-width="100px"
+      class="demo-ruleForm"
+    >
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="书籍名称" prop="name">
+            <el-input v-model="ruleForm.name"></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="出版时间" prop="pubDate">
+            <el-date-picker
+              v-model="ruleForm.pubDate"
+              type="date"
+              placeholder="选择出版时间"
+              value-format="yyyy-MM-dd"
+            >
+            </el-date-picker>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="书籍图片">
+            <el-upload
+              class="avatar-uploader"
+              ref="upload"
+              accept=".jpg,.png"
+              :headers="headerObj"
+              :action="uploadUrl"
+              :on-error="handleError"
+              :show-file-list="false"
+              :on-success="handleIconSuccess"
+              :before-upload="beforeIconUpload"
+              :on-change="handleChange"
+              :on-remove="handleRemove"
+            >
+              <img
+                v-if="ruleForm.thumb"
+                :src="OSSURL + ruleForm.thumb"
+                class="avatar"
+              />
+              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              <!-- 单纯用来刷新视图的变化的 -->
+              <el-input v-show="false" v-model="refresh"></el-input>
+            </el-upload>
+            <div>
+              <p style="color: #999">格式要求:</p>
+              <p style="color: #999; line-height: 1">
+                1、支持png,jpeg的图片格式
+              </p>
+              <p style="color: #999">2、最大可支持10M</p>
+            </div>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="书籍介绍" prop="description">
+            <el-input
+              type="textarea"
+              :rows="2"
+              placeholder="请输入介绍"
+              v-model="ruleForm.description"
+            ></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-form-item>
+          <el-button type="primary" @click="submitForm('ruleForm')"
+            >保存</el-button
+          >
+          <el-button @click="quxiao()">取消</el-button>
+        </el-form-item>
+      </el-row>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import * as common from "@/util/commonfn.js";
+export default {
+  components: {},
+  data() {
+    return {
+      refresh: "未刷新",
+      headerObj: {
+        token: window.localStorage.getItem("token"),
+      },
+      ruleForm: {},
+      rules: {
+        name: [{ required: true, message: "请输入书籍名称", trigger: "blur" }],
+        description: [
+          { required: true, message: "请输入书籍介绍", trigger: "blur" },
+        ],
+        pubDate: [
+          { required: true, message: "请输入出版时间", trigger: "blur" },
+        ],
+        // pic: [{ required: true, message: "请上传藏品图片", trigger: "blur" }],
+      },
+      token: window.localStorage.getItem("token"),
+      uploadUrl: `${this.$serverName}manage/book/upload`,
+      fileList: [],
+    };
+  },
+  props: {
+    layerid: {
+      //自动注入的layerid
+      type: String,
+      default: "",
+    },
+    iframeData: {
+      //传递的数据
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+  },
+  methods: {
+    quxiao(reload) {
+      this.$layer.close(this.layerid);
+      //点击取消 不刷新列表   点击确认 保存成功刷新列表
+      if (reload) {
+        this.$parent.getInformation();
+      }
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          if (!this["ruleForm"].thumb) {
+            common.tip("warning", "请上传图片");
+            return;
+          }
+          this.save();
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    async save() {
+      let { name, id, description, thumb, pubDate } = this.ruleForm;
+      let data = {
+        name,
+        id,
+        description,
+        thumb,
+        pubDate,
+      };
+      let result = await this.$http({
+        method: "post",
+        data,
+        url: `/manage/book/save`,
+      });
+      if (result["code"] === 0) {
+        common.tip("success", "保存成功");
+        this.quxiao(true);
+      } else {
+        common.tip("error", "保存失败,请联系管理员");
+      }
+    },
+    handleError() {},
+    handleIconSuccess(res) {
+      let { data } = res;
+      this.ruleForm.thumb = data.ossPath;
+      // 刷新下页面
+      this.refresh = "刷新了";
+    },
+    beforeIconUpload(file) {
+      let size = 10;
+      const isLt = file.size / 1024 / 1024 < size;
+      if (!isLt) {
+        this.$message.error(`上传头像图片大小不能超过 ${size}MB!`);
+        return isLt;
+      }
+    },
+    handleChange(file) {
+      this.fileList = this.fileList.length === 0 ? this.fileList : [];
+      this.fileList.push(file["raw"]);
+    },
+    handleRemove(file) {
+      let index = this.fileList.findIndex((item) => {
+        return item.uid === file.uid;
+      });
+      this.fileList.splice(index, 1);
+    },
+  },
+  watch: {
+    iframeData: {
+      handler: function () {
+        this.ruleForm = this.iframeData;
+      },
+      deep: true,
+      immediate: true,
+    },
+  },
+  created() {},
+};
+</script>
+
+<style lang="less" scoped>
+.Root {
+  width: 100%;
+  padding: 50px;
+}
+
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+  border: 1px dashed #d9d9d9;
+}
+</style>
+

+ 226 - 0
src/pages/news/bookList.vue

@@ -0,0 +1,226 @@
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span>关键字:</span>
+            <el-input
+              class="elInput"
+              v-model="params.searchKey"
+              placeholder="请输入关键字"
+            ></el-input>
+
+            <el-button
+              style="margin-left: 1.25rem"
+              type="primary"
+              @click="getInformation(true)"
+              >查询</el-button
+            >
+            <el-button type="primary" @click="edit({source:'0'}, 'add')">新增</el-button>
+          </div>
+          <div class="info-right"></div>
+        </div>
+        <el-table
+          :data="dataList"
+          height="61vh"
+          class="collection-con"
+          :tree-props="{ children: 'children' }"
+          row-key="id"
+          style="width: 100%"
+        >
+          <el-table-column
+            type="index"
+            label="序号"
+            :index="indexMethod"
+          ></el-table-column>
+          <el-table-column prop="name" label="书籍名称"></el-table-column>
+          <el-table-column prop="pubDate" label="出版日期"></el-table-column>
+          <el-table-column prop="createTime" label="发布时间"></el-table-column>
+
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span
+                class="o-span"
+                v-if="$role == 'sys_admin' || $role == 'sys_high'"
+                @click="edit(scope.row, 'edit')"
+                >编辑</span
+              >
+              <span
+                class="o-span"
+                v-if="
+                  scope.row.isIndex != '1' &&
+                  ($role == 'sys_admin' || $role == 'sys_high')
+                "
+                @click="del(scope.row)"
+                >删除</span
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="params.pageNum"
+            @size-change="handleSizeChange"
+            :page-size="params.pageSize"
+            :page-sizes="[10, 20, 50]"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from "@/components/main-top";
+import bookEdit from "@/pages/news/bookEdit";
+
+const crumbData = [
+  {
+    name: "书籍",
+    id: 2 - 2,
+  },
+];
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      crumbData,
+      dataList: [],
+      params: {
+        pageNum: 1,
+        pageSize: 10,
+        searchKey: ""
+      },
+      total: 0,
+      token: window.localStorage.getItem("token")
+    };
+  },
+  computed: {},
+  watch: {},
+  created() {
+    this.getInformation();
+  },
+  mounted() {},
+
+  methods: {
+    indexMethod(index) {
+      return (this.params.pageNum - 1) * this.params.pageSize + index + 1;
+    },
+    edit(item = {}, type) {
+      this.$layer.iframe({
+        content: {
+          content: bookEdit,
+          parent: this,
+          data: { iframeData: item },
+        },
+        area: ["900px", "600px"],
+        title: `${type === "add" ? "新增" : "编辑"}书籍内容`,
+        maxmin: false,
+        shade: false,
+        shadeClose: false,
+        cancel: () => {
+          //关闭弹窗事件
+          this.getInformation()
+        },
+      });
+    },
+    del(item) {
+      this.$confirm("是否确认删除这篇文章?", "提示", {
+        confirmButtonText: "是",
+        cancelButtonText: "否",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http
+            .get(`/manage/book/remove/${item.id}`, {})
+            .then((res) => 
+            
+            {
+              if (res.code === 0) {
+                this.$alert("删除成功", "提示", {
+                  confirmButtonText: "确定",
+                  callback: () => {
+                    this.getInformation();
+                  },
+                });
+              } else {
+                this.$notify.error({
+                  title: "错误",
+                  message: res.msg,
+                });
+              }
+            });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    handleCurrentChange(val) {
+      this.params.pageNum = val;
+      this.getInformation();
+    },
+    handleSizeChange(val) {
+      this.params.pageSize = val;
+      this.getInformation();
+    },
+    async getInformation(reload = false) {
+      if (reload) {
+        this.params.pageNum = 1;
+        this.dataList = [];
+      }
+      let result = await this.$http({
+        method: "post",
+        data: this.params,
+        url: "/manage/book/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.dataList = result.data.list;
+      this.total = result.data.total;
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow: auto;
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+</style>
+

+ 174 - 0
src/pages/news/newEdit.vue

@@ -0,0 +1,174 @@
+<template>
+  <div class="Root">
+    <el-form
+      :model="form"
+      :rules="rules"
+      ref="form"
+      label-width="100px"
+      class="demo-ruleForm"
+    >
+
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="来源" prop="source">
+            <el-radio-group v-model="form.source">
+              <el-radio label="edit">编辑</el-radio>
+              <el-radio label="wechat">微信公众号</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="标题" prop="name" maxlength="30">
+            <el-input v-model="form.name"></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="类别" prop="type">
+            <el-select v-model="form.type" placeholder="请选择类别">
+              <el-option label="近期新闻" value="news"></el-option>
+              <el-option label="专项活动" value="activity"></el-option>
+              <el-option label="信息公开" value="info"></el-option>
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row v-if="form.source === 'edit'">
+        <el-col :span="24">
+          <el-form-item label="内容" prop="content" maxlength="30">
+            <vue-editor class="quill-editor" v-model="form.content" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+       <el-row v-if="form.source === 'wechat'">
+        <el-col :span="24">
+          <el-form-item label="链接" prop="wxUrl" maxlength="30">
+            <el-input v-model="form.wxUrl"></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-col :span="24">
+          <el-form-item>
+            <el-button type="primary" @click="submitForm('form')"
+              >保存</el-button
+            >
+            <el-button @click="quxiao()">取消</el-button>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import { VueEditor } from "vue2-editor";
+import * as common from "@/util/commonfn.js";
+export default {
+  components: {
+    VueEditor,
+  },
+  data() {
+    return {
+      headerObj: {
+        token: window.localStorage.getItem("token"),
+      },
+      fileList: [],
+      form: {
+        name: "",
+        content: "",
+        type: "",
+        source:"edit",
+        wxUrl:""
+
+      },
+      rules: {
+        name: [{ required: true, message: "请输入标题", trigger: "blur" }],
+        type: [{ required: true, message: "请选择类别", trigger: "blur" }],
+        source: [{ required: true, message: "请选择来源", trigger: "blur" }],
+        content: [{ required: true, message: "请输入内容", trigger: "blur" }],
+        wxUrl: [{ required: true, message: "请输入链接", trigger: "blur" }]
+      },
+      uploadUrl: `${this.$serverName}manage/news/upload`,
+    };
+  },
+  props: {
+    layerid: {
+      //自动注入的layerid
+      type: String,
+      default: "",
+    },
+    iframeData: {
+      //传递的数据
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+  },
+  methods: {
+    quxiao(reload) {
+      this.$layer.close(this.layerid);
+      //点击取消 不刷新列表   点击确认 保存成功刷新列表
+      if (reload) {
+        this.$parent.getInformation();
+      }
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.save();
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    async save() {
+      // console.log('this.form',this.form)
+      let { content, name, type, id, code,source,wxUrl } = this.form;
+      let data = { content, name, type, id, code,source,wxUrl};
+      let result = await this.$http({
+        method: "post",
+        data,
+        url: `/manage/news/save`,
+      });
+      if (result["code"] === 0) {
+        common.tip("success", "保存成功");
+        this.quxiao(true);
+      } else {
+        common.tip("error", "保存失败,请联系管理员");
+      }
+    },
+  },
+  watch: {
+    iframeData: {
+      handler: function () {
+        this.form = this.iframeData;
+      },
+      deep: true,
+      immediate: true,
+    },
+  },
+  created() {
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.quill-editor {
+  line-height: normal;
+}
+.Root {
+  padding: 50px;
+}
+.ivu-upload {
+  display: none;
+}
+</style>
+

+ 253 - 0
src/pages/news/newsList.vue

@@ -0,0 +1,253 @@
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span>类别:</span>
+            <el-select v-model="params.type" placeholder="请选择类别">
+              <el-option
+                v-for="item in options"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              >
+              </el-option>
+            </el-select>
+            &nbsp;
+            <span>关键字:</span>
+            <el-input
+              class="elInput"
+              v-model="params.searchKey"
+              placeholder="请输入关键字"
+            ></el-input>
+
+            <el-button
+              style="margin-left: 1.25rem"
+              type="primary"
+              @click="getInformation(true)"
+              >查询</el-button
+            >
+            <el-button type="primary" @click="edit({source:'edit'}, 'add')">新增</el-button>
+          </div>
+          <div class="info-right"></div>
+        </div>
+        <el-table
+          :data="tableData"
+          height="61vh"
+          class="collection-con"
+          :tree-props="{ children: 'children' }"
+          row-key="id"
+          style="width: 100%"
+        >
+          <el-table-column
+            type="index"
+            label="序号"
+            :index="indexMethod"
+          ></el-table-column>
+          <el-table-column prop="name" label="文章标题"></el-table-column>
+          <el-table-column prop="userName" label="发布用户"></el-table-column>
+          <el-table-column prop="createTime" label="发布时间"></el-table-column>
+
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span
+                class="o-span"
+                v-if="$role == 'sys_admin' || $role == 'sys_high'"
+                @click="edit(scope.row, 'edit')"
+                >编辑</span
+              >
+              <span
+                class="o-span"
+                v-if="
+                  scope.row.isIndex != '1' &&
+                  ($role == 'sys_admin' || $role == 'sys_high')
+                "
+                @click="del(scope.row)"
+                >删除</span
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="params.pageNum"
+            @size-change="handleSizeChange"
+            :page-size="params.pageSize"
+            :page-sizes="[10, 20, 50]"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from "@/components/main-top";
+import newEdit from "@/pages/news/newEdit";
+
+const crumbData = [
+  {
+    name: "资讯内容",
+    id: 2 - 1,
+  },
+];
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      crumbData,
+      tableData: [],
+      params: {
+        pageNum: 1,
+        pageSize: 10,
+        searchKey: "",
+        type:""
+      },
+      total: 0,
+      token: window.localStorage.getItem("token"),
+      options: [
+        {value:'',label:'全部'},
+        {
+          value: "news",
+          label: "近期新闻",
+        },
+        {
+          value: "info",
+          label: "专项活动",
+        },
+        {
+          value: "activity",
+          label: "信息公开",
+        },
+      ]
+    };
+  },
+  computed: {},
+  watch: {},
+  created() {
+    this.getInformation();
+  },
+  mounted() {},
+
+  methods: {
+    indexMethod(index) {
+      return (this.params.pageNum - 1) * this.params.pageSize + index + 1;
+    },
+    edit(item = {}, type) {
+      this.$layer.iframe({
+        content: {
+          content: newEdit,
+          parent: this,
+          data: { iframeData: item },
+        },
+        area: ["900px", "600px"],
+        title: `${type === "add" ? "新增" : "编辑"}资讯内容`,
+        maxmin: false,
+        shade: false,
+        shadeClose: false,
+        cancel: () => {
+          //关闭弹窗事件
+          this.getInformation()
+        },
+      });
+    },
+    del(item) {
+      this.$confirm("是否确认删除这篇文章?", "提示", {
+        confirmButtonText: "是",
+        cancelButtonText: "否",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http
+            .get(`/manage/news/remove/${item.id}`, {})
+            .then((res) => 
+            
+            {
+              if (res.code === 0) {
+                this.$alert("删除成功", "提示", {
+                  confirmButtonText: "确定",
+                  callback: () => {
+                    this.getInformation();
+                  },
+                });
+              } else {
+                this.$notify.error({
+                  title: "错误",
+                  message: res.msg,
+                });
+              }
+            });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    handleCurrentChange(val) {
+      this.params.pageNum = val;
+      this.getInformation();
+    },
+    handleSizeChange(val) {
+      this.params.pageSize = val;
+      this.getInformation();
+    },
+    async getInformation(reload = false) {
+      if (reload) {
+        this.params.pageNum = 1;
+        this.tableData = [];
+      }
+      let result = await this.$http({
+        method: "post",
+        data: this.params,
+        url: "/manage/news/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.tableData = result.data.list;
+      this.total = result.data.total;
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow: auto;
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+</style>
+

+ 310 - 0
src/pages/questionnaire/questionnaireEdit.vue

@@ -0,0 +1,310 @@
+<template>
+  <div class="Root">
+    <el-form
+      :model="form"
+      :rules="rules"
+      ref="form"
+      label-width="100px"
+      class="demo-ruleForm"
+    >
+      <el-form-item label="标题:" prop="name">
+        <el-input v-model="form.name"></el-input>
+      </el-form-item>
+
+      <template>
+        <div
+          class="question"
+          v-for="(item, index) in form.question"
+          :key="index"
+        >
+          <div class="close" @click="delSubject(item)">X</div>
+          <div class="q-index">第{{ index + 1 }}题</div>
+          <el-form-item label="题目:">
+            <el-input v-model="item.question"></el-input>
+          </el-form-item>
+          <el-form-item label="类型:">
+            <el-select v-model="item.type" placeholder="请选择">
+              <el-option
+                v-for="item in topicTypes"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              >
+              </el-option>
+            </el-select>
+          </el-form-item>
+
+          <el-form-item
+            :label="`选项:${index + 1}`"
+            v-for="(option, index) in item.answer"
+            :key="index"
+          >
+            <div class="ipt">
+              <el-input v-model="option.value" required></el-input>
+              <div class="ipt-close" @click="delOption(item, option)">X</div>
+            </div>
+          </el-form-item>
+          <div class="addOption">
+            <el-button class="addOp-btn" type="primary" @click="addOption(item)"
+              >添加选项+</el-button
+            >
+          </div>
+        </div>
+      </template>
+
+      <el-form-item prop="addQuestion">
+        <el-button class="add-btn" type="primary" @click="addSubject()"
+          >添加题目+</el-button
+        >
+      </el-form-item>
+
+      <el-row>
+        <el-col :span="24">
+          <el-form-item>
+            <el-button type="primary" @click="submitForm('form')"
+              >保存</el-button
+            >
+            <el-button @click="quxiao()">取消</el-button>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import * as common from "@/util/commonfn.js";
+import { v4 as uuidv4 } from "uuid";
+export default {
+  components: {},
+  data() {
+    var buttonRequire = (rule, value, callback) => {
+      if (this.form.question.length === 0) {
+        callback(new Error("请添加添加选项"));
+      }else {
+        callback()
+      }
+    };
+    return {
+      headerObj: {
+        token: window.localStorage.getItem("token"),
+      },
+      form: {},
+      topicTypes: [
+        { label: "单选", value: "radio" },
+        { label: "多选", value: "multiple" },
+      ],
+      rules: {
+        name: [{ required: true, message: "请输入标题", trigger: "blur" }],
+        addQuestion: [{ validator: buttonRequire, trigger: "blur" }],
+      },
+      token: window.localStorage.getItem("token"),
+    };
+  },
+  props: {
+    layerid: {
+      //自动注入的layerid
+      type: String,
+      default: "",
+    },
+    iframeData: {
+      //传递的数据
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+    type: {
+      type: String,
+      default: () => {
+        return "add";
+      },
+    },
+  },
+  methods: {
+    addSubject() {
+      this.form.question.push({
+        vid: uuidv4(),
+        question: "",
+        type: "",
+        answer: [],
+      });
+    },
+    delSubject(item) {
+      this.$confirm("是否确认删除题目", "提示", {
+        confirmButtonText: "是",
+        cancelButtonText: "否",
+        type: "warning",
+      })
+        .then(() => {
+          this.form.question = this.form.question.filter(
+            (e) => e.id != item.id
+          );
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    addOption(question) {
+      question.answer.push({ vid: uuidv4(), value: "" });
+    },
+    delOption(options, option) {
+      this.form.question = this.form.question.map((e) => {
+        if (options.vid === e.vid) {
+          return {
+            ...e,
+            answer: e.answer.filter((e1) => e1.vid != option.vid),
+          };
+        } else {
+          return { ...e };
+        }
+      });
+    },
+    quxiao(reload) {
+      this.$layer.close(this.layerid);
+      //点击取消 不刷新列表   点击确认 保存成功刷新列表
+      if (reload) {
+        this.$parent.getInformation();
+      }
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.save();
+        } else {
+          return false;
+        }
+      });
+    },
+    async save() {
+      let questionData = this.form.question.map((item) => {
+        let myAnswer = [];
+        item.answer.map((answer) => {
+          myAnswer.push({ value: answer.value, vid: answer.vid });
+        });
+        return { ...item, answer: myAnswer };
+      });
+      questionData = { question: questionData };
+      let questionResult = await this.$http({
+        method: "post",
+        data: questionData,
+        url: `/cms/questionGroup/question/save`,
+      });
+      if (questionResult.code === 0) {
+        let questionnaireData = {
+          name: this.form.name,
+          id:this.form.id || '',
+          questionIds:
+            (questionResult.data && questionResult.data.join()) || "",
+        };
+        let questionnaireResult = await this.$http({
+          method: "post",
+          data: questionnaireData,
+          url: `/cms/questionGroup/save`,
+        });
+        if (questionnaireResult.code === 0) {
+          common.tip("success", "保存成功");
+          this.quxiao(true)
+          
+        } else {
+          common.tip("error", "保存失败,请联系管理员");
+        }
+      }
+    },
+    async getQuestionnaire(questionnaireId) {
+      let questionnaireResult = await this.$http({
+        method: "get",
+        url: `/cms/questionGroup/detail/${questionnaireId}`,
+      });
+      let questionnaireList = questionnaireResult.data.answer.map(item=>{
+        return {...item,answer:JSON.parse(item.answer)}
+      })
+      this.form = {
+        name:questionnaireResult.data.entity.name,
+        id:questionnaireResult.data.entity.id,
+        question:questionnaireList
+      }
+    },
+  },
+  watch: {
+    iframeData: {
+      handler: function () {
+        this.form = this.iframeData;
+      },
+      deep: true,
+      immediate: true,
+    },
+    type: {
+      handler: function () {
+        this.Type = this.type;
+      },
+      deep: true,
+      immediate: true,
+    },
+  },
+  created() {
+    if(this.type === 'edit') {
+      this.getQuestionnaire(this.form.id);
+    }
+    
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.Root {
+  padding: 50px;
+}
+.demo-ruleForm {
+  width: 220%;
+  .addOption {
+    width: 100%;
+    margin: 20px 0;
+    .add-btn {
+      width: 50%;
+      display: block;
+      margin: 0 auto;
+    }
+  }
+}
+.question {
+  border: 1px solid #ccc;
+  position: relative;
+  margin-bottom: 20px;
+  margin-left: 30px;
+  .close {
+    position: absolute;
+    right: 20px;
+    top: 20px;
+    color: red;
+    cursor: pointer;
+  }
+  .q-index {
+    width: 100%;
+    text-align: center;
+    padding: 20px 0;
+    margin-bottom: 10px;
+  }
+  .ipt {
+    position: relative;
+    .ipt-close {
+      position: absolute;
+      right: 20px;
+      top: 0;
+      cursor: pointer;
+      color: red;
+    }
+  }
+  .addOption {
+    width: 100%;
+    .addOp-btn {
+      display: block;
+      margin: 0 auto;
+    }
+  }
+}
+</style>
+

+ 250 - 0
src/pages/questionnaire/questionnaireList.vue

@@ -0,0 +1,250 @@
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span>发布时间:</span>
+            <el-date-picker
+              v-model="params.startTime"
+              format="yyyy-MM-dd"
+              value-format="yyyy-MM-dd"
+              placeholder="选择开始时间"
+            >
+            </el-date-picker>
+
+            <el-button
+              style="margin-left: 1.25rem"
+              type="primary"
+              @click="getInformation(true)"
+              >查询</el-button
+            >
+            <el-button type="primary" @click="edit({name:'', question: []}, 'add')">新增</el-button>
+          </div>
+        </div>
+
+        <el-table
+          :data="selectedData"
+          row-key="id"
+          style="width: 100%; margin-bottom: 50px"
+        >
+          <el-table-column
+            type="index"
+            label="序号"
+            :index="indexMethod"
+          ></el-table-column>
+          <el-table-column prop="name" label="问卷名称"></el-table-column>
+          <el-table-column prop="userName" label="发布用户"></el-table-column>
+          <el-table-column prop="createTime" label="发布时间"></el-table-column>
+        </el-table>
+
+        <el-table
+          :data="tableData"
+          height="61vh"
+          class="collection-con"
+          :tree-props="{ children: 'children' }"
+          row-key="id"
+          style="width: 100%"
+        >
+          <el-table-column
+            type="index"
+            label="序号"
+            :index="indexMethod"
+          ></el-table-column>
+          <el-table-column prop="name" label="问卷名称"></el-table-column>
+          <el-table-column prop="userName" label="发布用户"></el-table-column>
+          <el-table-column prop="createTime" label="发布时间"></el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span class="o-span" @click="show(scope.row)">查看</span>
+              <span class="o-span" @click="edit(scope.row, 'edit')">编辑</span>
+              <span class="o-span" @click="del(scope.row)">删除</span>
+              <span class="o-span" @click="setAsShow(scope.row)"
+                >设置为展示</span
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="params.pageNum"
+            @size-change="handleSizeChange"
+            :page-size="params.pageSize"
+            :page-sizes="[10, 20, 50]"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import MainTop from "@/components/main-top";
+import questionnaireEdit from "@/pages/questionnaire/questionnaireEdit";
+import * as common from "@/util/commonfn.js";
+const crumbData = [
+  {
+    name: "问卷调查",
+    id: 5 - 2,
+  },
+];
+
+export default {
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      activitySort: [],
+      crumbData,
+      tableData: [],
+      params: {
+        pageNum: 1,
+        pageSize: 10,
+      },
+      total: 0,
+      selectedData: [],
+    };
+  },
+  computed: {},
+  watch: {},
+  created() {
+    this.getInformation();
+    this.getActivitySort();
+  },
+  mounted() {},
+
+  methods: {
+    indexMethod(index) {
+      return (this.params.pageNum - 1) * this.params.pageSize + index + 1;
+    },
+    show(item) {
+      this.$router.push({ path: "/questionnaireResult/"+item.id });
+    },
+    edit(item = {}, type) {
+      this.$layer.iframe({
+        content: {
+          content: questionnaireEdit,
+          parent: this,
+          data: { iframeData: item,type },
+        },
+        area: ["900px", "600px"],
+        title: `${type === "add" ? "新增" : "编辑"}问卷调查`,
+        maxmin: false,
+        shade: false,
+        shadeClose: false,
+        cancel: () => {
+          //关闭弹窗事件
+          this.getInformation();
+        },
+      });
+    },
+    del(item) {
+      this.$confirm("是否确认删除问卷调查?", "提示", {
+        confirmButtonText: "是",
+        cancelButtonText: "否",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http.get(`/cms/questionGroup/remove/${item.id}`, {}).then((res) => {
+            if (res.code === 0) {
+              this.$alert("删除成功", "提示", {
+                confirmButtonText: "确定",
+                callback: () => {
+                  this.getInformation();
+                },
+              });
+            } else {
+              this.$notify.error({
+                title: "错误",
+                message: res.msg,
+              });
+            }
+          });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    handleCurrentChange(val) {
+      this.params.pageNum = val;
+      this.getInformation();
+    },
+    handleSizeChange(val) {
+      this.params.pageSize = val;
+      this.getInformation();
+    },
+    async getInformation(reload = false) {
+      if (reload) {
+        this.params.pageNum = 1;
+        this.tableData = [];
+      }
+      this.params.startTime =
+        (this.params.startTime && `${this.params.startTime} 00:00:00`) || "";
+      let result = await this.$http({
+        method: "post",
+        data: this.params,
+        url: "/cms/questionGroup/list",
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.tableData = result.data.list;
+      this.total = result.data.total;
+      this.selectedData = this.tableData.filter(item=>item.display === 1);
+    },
+    async getActivitySort() {
+      this.activitySort = [
+        { id: "online", name: "线上活动" },
+        { id: "volunteer", name: "志愿者服务" },
+      ];
+    },
+    async setAsShow(item={}) {
+      let result = await this.$http({
+        method: "get",
+        url: `/cms/questionGroup/display/${item.id}`
+      });
+      if (result.code == 0) {
+        common.tip("success", "设置成功");
+        this.getInformation();
+      } else {
+        common.tip("error", "设置失败,请联系管理员");
+      }
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow: auto;
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+</style>
+

+ 148 - 0
src/pages/questionnaire/questionnaireResult.vue

@@ -0,0 +1,148 @@
+<template>
+  <div>
+    <main-top :crumb="crumbData" :questionBack="true">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="desc">
+          <div class="desc-title">
+            <div class="txt">问卷名称:&nbsp;&nbsp;{{ detail.name }}</div>
+            <div class="time">发布时间:&nbsp;&nbsp;{{ detail.createTime }}</div>
+          </div>
+          <div class="desc-data">
+            显示数据:&nbsp;&nbsp;
+            <el-radio v-model="showDataType" label="0">百分比</el-radio>
+            <el-radio v-model="showDataType" label="1">计数</el-radio>
+          </div>
+        </div>
+        <el-table
+          :data="tableData"
+          height="61vh"
+          class="collection-con"
+          :tree-props="{ children: 'children' }"
+          row-key="id"
+          style="width: 100%"
+        >
+          <el-table-column prop="num" label="题号"></el-table-column>
+          <el-table-column
+            :prop="key"
+            :label="key"
+            v-for="(value, key) in maxObject"
+            :key="key"
+          >
+            <template slot-scope="scope">
+              {{ handleData(scope.row[key])}}
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import MainTop from "@/components/main-top";
+const crumbData = [
+  {
+    name: "问卷调查结果",
+    id: 5 - 2,
+  },
+];
+
+export default {
+  components: {
+    MainTop,
+  },
+  data() {
+    return {
+      crumbData,
+      detail: {},
+      tableData: [],
+      showDataType: "0",
+      questionGroupId: "",
+      maxObject: [],
+    };
+  },
+  computed: {},
+  watch: {
+    showDataType: {
+      handler() {
+        this.getInformation();
+      },
+    },
+  },
+  created() {
+    this.questionGroupId =
+      (this.$route.params && this.$route.params.questionGroupId) || "";
+    this.getInformation();
+  },
+  mounted() {},
+
+  methods: {
+    handleData(data) {
+      return (data !== 0 && (!data || data === 'null' )) ? '-': this.showDataType==='0'? String(data*100).slice(0,4)+'%' :data
+    },
+    async getInformation() {
+      let result = await this.$http({
+        method: "get",
+        url: `/manage/countAnswer/detail/${this.questionGroupId}/${this.showDataType}`,
+      });
+      if (result.code !== 0) {
+        return;
+      }
+      this.detail = result.data;
+      this.tableData = this.detail.answer;
+      let maxLen = 0;
+      let maxNum = 0;
+      let maxArr = [];
+      this.tableData.map((item) => {
+        if (Object.entries(item).length > maxLen) {
+          maxLen = Object.entries(item).length;
+          maxNum = item.num;
+        }
+      });
+      maxArr = this.tableData.filter((item) => item.num === maxNum);
+      this.maxObject = { ...maxArr[0] };
+      delete this.maxObject.num;
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow: auto;
+}
+
+.info-top {
+  padding: 1.25rem 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 0.0625rem #a5a5a5 solid;
+}
+.desc {
+  padding: 20px;
+  .desc-title {
+    margin-bottom: 20px;
+    display: flex;
+    .txt {
+      margin-right: 50px;
+    }
+    .time {
+    }
+  }
+}
+</style>
+

+ 363 - 0
src/pages/show/parts.vue

@@ -0,0 +1,363 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con" class="con-btn">
+        <el-button type="primary" @click="$router.back()">返回</el-button>
+      </div>
+    </main-top>
+      <div class="table-interface">
+        <div class="collection-con">
+          <div class="c-left">
+            <iframe v-if="part.displayModel == 0" :src="part.webSite" frameborder="0"></iframe>
+            <img v-else :src="part.ico" alt="">
+          </div>
+          <div class="c-right theme-color">
+            <div class="c-h1">{{part.name}}</div>
+            <p class="c-title">
+              <span>部件详细信息</span>
+              <i class="iconfont iconsys_edit" @click="goto"></i>
+            </p>
+            <p>部件类别:{{part.typeName}}</p>
+            <p>所属楼体:{{BLOCK[part.block]}}</p>
+            <p>部件位置:<span v-html="ZONE[part.zone]"></span></p>
+            <p>是否在程序显示:
+              <el-switch
+                @change="handleShow"
+                v-model="part.display">
+              </el-switch>
+            </p>
+            <p class="c-title" style="margin-bottom:0">
+              <span>部件介绍</span>
+            </p>
+            <p v-html="part.content||'暂无介绍'" style="margin-top:20px"></p>
+
+            <p class="c-title">
+              <span>多媒体资料</span>
+              <i class="iconfont iconsys_down" @click="apply(file)"></i>
+            </p>
+            
+            <div class="media-cls">
+              <p v-if="file.length===0" style="color:#999">暂无内容</p>
+              <p v-for="(sub,idx) in file" :key="idx">{{sub.fileName}}</p>
+            </div>
+          </div>
+        </div>
+      </div>
+          <el-dialog title="提交下载申请" :visible.sync="dialogFormVisible" width="40%">
+      <div class="dialog">
+        <p>请选择要下载的内容:</p>
+        <div class="content">
+            <el-checkbox-group v-model="checkList" @change='handleChange'>
+              <div v-for="(sub,idx) in activeFiles" :key="idx">
+                <el-checkbox :label="sub.id" :false-label="''" :true-label="''">{{sub.fileName}}</el-checkbox>
+              </div>
+            </el-checkbox-group>
+        </div>
+        <p>请填写下载用途:</p>
+        <div class="content textarea">
+          <el-input
+            type="textarea"
+            :rows="2"
+            placeholder="请输入内容"
+            v-model="textarea">
+          </el-input>
+        </div>
+        <p>请选择审核人:</p>
+        <ul class="content">
+          <li v-for="(item,i) in adminList" :key="i">
+            <el-radio v-model="radio" :label="item.id">{{item.userName}}</el-radio>
+          </li>
+        </ul>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+        <el-button type="primary" @click="applyDownload">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+
+const crumbData = [
+  {
+    name: '部件信息',
+    id: 0
+  },
+  {
+    name: '查看详情',
+    id: 1
+  }
+]
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop
+  },
+  data () {
+    return {
+      crumbData,
+      id: this.$route.params.id,
+      type: 'picture',
+      realType: '',
+      file:'',
+      part:'',
+      value1:true,      
+      dialogFormVisible: false,
+      checkList: [],
+      textarea:'',
+      activeFiles:'',
+      adminList:[],
+      radio:''
+    }
+  },
+  methods: {
+     handleChange(){
+    },
+    async getDetail(){
+      let result = await this.$http({
+        method: 'get',
+        headers: {
+          token: window.localStorage.getItem('token')
+        },
+        url: `/manage/part/detail/${this.id}`
+      })
+
+      this.dialogFormVisible = false
+      this.file = result.data.file
+      this.part = result.data.part
+      this.part.display = Boolean(this.part.display)
+      
+    },
+    apply(files){
+      if (files.length===0) {
+        return
+      }
+      this.dialogFormVisible = true
+      this.activeFiles = files
+
+      this.getAdminList()
+    },
+
+    async applyDownload(){
+      
+      if (!this.radio||!this.checkList.length) {
+        return this.$alert("请填写勾选信息", "提示", {
+            confirmButtonText: "确定",
+            callback: () => {
+              return
+            },
+          })
+      }
+      
+      let params ={
+        auditId: this.radio,
+        fileIds: this.checkList.join(','),
+        fkId: '',
+        name: this.part.name,
+        reason: this.textarea,
+        type: 'part'
+      }
+    let result = await this.$http({
+        method: 'post',
+        data:params,
+        headers: {
+          token: window.localStorage.getItem('token')
+        },
+        url: '/manage/download/save'
+      })
+
+      
+      if (result.code === 0) {
+        this.$alert('申请成功', '提示', {
+          confirmButtonText: '确定',
+          callback: () => {
+            this.getDetail()
+          }
+        })
+      } else {
+        this.$notify.error({
+          title: '错误',
+          message: result.msg
+        })
+      }
+
+    },
+
+    async getAdminList(){
+    let result = await this.$http({
+        method: 'get',
+        headers: {
+          token: window.localStorage.getItem('token')
+        },
+        url: '/manage/download/admin'
+      })
+
+      this.adminList = result.data
+    },
+
+    goto () {
+      this.$router.push({ name: 'edit-parts', params: { type: 1,id:this.part.id } })
+    },
+    async handleShow(e){
+      this.part['display'] = e
+      let params = {}
+      Object.assign(params,this.part,{
+        display:e|0
+      })
+      await this.$http({
+        method: "post",
+        data: params,
+        headers: {
+          token: window.localStorage.getItem("token")
+        },
+        url: `/manage/part/save`
+      });
+    }
+  },
+  mounted () {
+    this.getDetail()
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+  background: #fff;
+  padding: 2.625rem 1.25rem;
+}
+
+.collection-con{
+  display: flex;
+}
+
+.c-left{
+  flex: 3;
+  margin-right: 20px;
+}
+
+.c-left p{
+  margin: 10px 20px;
+}
+
+.c-left iframe,.c-left img{
+  width: 100%;
+  min-height: 70vh;
+}
+
+.c-right{
+  flex: 1;
+  .c-h1{
+    color: #B63C25;
+    font-size: 1.25rem;
+    font-weight: bold;
+  }
+}
+
+.c-right .c-title{
+  font-weight: bold;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px solid #532F1C;
+  color: #532F1C;
+  font-size: 1.125rem;
+}
+
+.edit{
+  cursor: pointer;
+}
+.c-right p{
+  margin: 40px 20px 40px 0;
+  word-break: break-all;
+  line-height: 1.5;
+  font-size: 1rem;
+}
+.con-btn{
+  padding-right: 1.25rem;
+}
+
+.media-cls{
+  color: rgba(0, 176, 255, 1);
+  cursor: pointer;
+  margin-top: 20px;
+  p{
+    line-height: 2;
+    margin: 0;
+  }
+}
+
+.iconfont{
+  cursor: pointer;
+}
+
+.dialog{
+  .content{
+    border: .0625rem solid #ccc;
+    padding: .625rem;
+    margin: .625rem auto;
+    div,li{
+      line-height: 2;
+    }
+  }
+  .textarea{
+    padding: 0;
+    border: none;
+  }
+}
+
+</style>
+
+<style>
+.ql-picker-label {
+  line-height: 1;
+  overflow: hidden;
+}
+
+.avatar-uploader .el-upload {
+  border: 1px dashed #000;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+.iconfont{
+  font-size: 20px;
+}
+
+</style>

+ 245 - 0
src/pages/show/roam.vue

@@ -0,0 +1,245 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con" class="con-btn">
+        <el-button type="primary" @click="$router.back()">返回</el-button>
+      </div>
+    </main-top>
+      <div class="table-interface">
+        <div class="collection-con">
+          <div class="c-left">
+            <video v-if="detail.displayModel === 2" :src="detail.video||detail.webSite" autoplay loop></video>
+            <iframe v-else :src="detail.webSite" frameborder="0"></iframe>
+          </div>
+          <div class="c-right theme-color">
+            <div class="c-h1">{{detail.name}}</div>
+            <p class="c-title">
+              <span>漫游信息</span>
+              <i class="iconfont iconsys_edit" @click="goto"></i>
+            </p>
+            <p>漫游类别:{{detail.typeName}}</p>
+            <p>所属楼体:{{BLOCK[detail.block]}}</p>
+            <p>漫游位置:<span v-html="ZONE[detail.zone]"></span></p>
+            <p>是否在程序显示:
+              <el-switch
+                @change="handleShow"
+                v-model="detail.display">
+              </el-switch>
+            </p>
+            <p class="c-title" style="margin-bottom:0">
+              <span>漫游介绍</span>
+            </p>
+            <p v-html="detail.content||'暂无介绍'" style="margin-top:20px"></p>
+
+          </div>
+        </div>
+      </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+
+const crumbData = [
+  {
+    name: '漫游信息',
+    id: 0
+  },
+  {
+    name: '查看详情',
+    id: 1
+  }
+]
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop
+  },
+  data () {
+    return {
+      crumbData,
+      detail: '',
+      id: this.$route.params.id,
+      type: 'picture',
+      realType: '',
+      value1:true
+    }
+  },
+  methods: {
+    async getDetail(){
+      let result = await this.$http({
+        method: 'get',
+        headers: {
+          token: window.localStorage.getItem('token')
+        },
+        url: `/manage/roam/detail/${this.id}`
+      })
+
+      this.detail = result.data
+      this.detail.display = Boolean(this.detail.display)
+
+    },
+
+    goto () {
+      this.$router.push({ name: 'edit-roam', params: { type: 1, id:this.detail.id} })
+    },
+    async handleShow(e){
+      this.detail['display'] = e
+      let params = {}
+      Object.assign(params,this.detail,{
+        display:e|0
+      })
+      await this.$http({
+        method: "post",
+        data: params,
+        headers: {
+          token: window.localStorage.getItem("token")
+        },
+        url: `/manage/roam/save`
+      });
+    }
+  },
+  mounted () {
+    this.getDetail()
+  }
+}
+</script>
+<style lang="less" scoped>
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+  background: #fff;
+  padding: 2.625rem 1.25rem;
+}
+
+.collection-con{
+  display: flex;
+}
+
+.c-left{
+  flex: 3;
+  margin-right: 20px;
+}
+
+.c-left p{
+  margin: 10px 20px;
+}
+
+.c-left iframe,.c-left video{
+  width: 100%;
+  min-height: 70vh;
+}
+
+.c-right{
+  flex: 1;
+  .c-h1{
+    color: #B63C25;
+    font-size: 1.25rem;
+    font-weight: bold;
+  }
+}
+
+.c-right .c-title{
+  font-weight: bold;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px solid #532F1C;
+  color: #532F1C;
+  font-size: 1.125rem;
+}
+
+.edit{
+  cursor: pointer;
+}
+.c-right p{
+  margin: 40px 20px 40px 0;
+  word-break: break-all;
+  line-height: 1.5;
+  font-size: 1rem;
+}
+.con-btn{
+  padding-right: 1.25rem;
+}
+
+.media-cls{
+  color: rgba(0, 176, 255, 1);
+  cursor: pointer;
+  margin-top: 20px;
+  p{
+    line-height: 2;
+    margin: 0;
+  }
+}
+
+.iconfont{
+  cursor: pointer;
+}
+
+.dialog{
+  .content{
+    border: .0625rem solid #ccc;
+    padding: .625rem;
+    margin: .625rem auto;
+    div,li{
+      line-height: 2;
+    }
+  }
+  .textarea{
+    padding: 0;
+    border: none;
+  }
+}
+
+</style>
+
+<style>
+.ql-picker-label {
+  line-height: 1;
+  overflow: hidden;
+}
+
+.avatar-uploader .el-upload {
+  border: 1px dashed #000;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+.iconfont{
+  font-size: 20px;
+}
+
+</style>

+ 236 - 0
src/pages/show/structure.vue

@@ -0,0 +1,236 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con" class="con-btn">
+        <el-button type="primary" @click="$router.back()">返回</el-button>
+      </div>
+    </main-top>
+      <div class="table-interface">
+                <div class="collection-con">
+          <div class="c-left">
+            <iframe v-if="detail.webSite" :src="detail.webSite||detail.ico" frameborder="0"></iframe>
+            <img v-else :src="detail.ico" alt="">
+          </div>
+          <div class="c-right theme-color">
+            <div class="c-h1">{{detail.name}}</div>
+            <p class="c-title">
+              <span>结构信息</span>
+              <i class="iconfont iconsys_edit" @click="goto"></i>
+            </p>
+            <p>所属楼体:{{BLOCK[detail.block]}}</p>
+            <p class="c-title" style="margin-bottom:0">
+              <span>结构介绍</span>
+            </p>
+            <p v-html="detail.content||'暂无介绍'" style="margin-top:20px"></p>
+          </div>
+        </div>
+      </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from '@/components/main-top'
+
+const crumbData = [
+  {
+    name: '结构信息',
+    id: 0
+  },
+  {
+    name: '查看详情',
+    id: 1
+  }
+]
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop
+  },
+  data () {
+    return {
+      crumbData,
+      detail: '',
+      id: this.$route.params.id,
+      type: 'picture',
+      realType: '',
+      value1:true
+    }
+  },
+  methods: {
+    async getDetail(){
+      let result = await this.$http({
+        method: 'get',
+        headers: {
+          token: window.localStorage.getItem('token')
+        },
+        url: `/manage/structure/detail/${this.id}`
+      })
+
+      this.detail = result.data
+    },
+
+    goto () {
+      this.$router.push({ name: 'edit-structure', params: { type: 1, id:this.detail.id} })
+    },
+    async handleShow(e){
+      this.detail['display'] = e
+      console.log(this.detail['display']);
+      let params = {}
+      Object.assign(params,this.detail,{
+        display:e|0
+      })
+      await this.$http({
+        method: "post",
+        data: params,
+        headers: {
+          token: window.localStorage.getItem("token")
+        },
+        url: `/manage/structure/save`
+      });
+    }
+  },
+  mounted () {
+    this.getDetail()
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.top-body{
+  border-top: .0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+
+.table-interface{
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+  background: #fff;
+  padding: 2.625rem 1.25rem;
+}
+
+.collection-con{
+  display: flex;
+}
+
+.c-left{
+  flex: 3;
+  margin-right: 20px;
+}
+
+.c-left p{
+  margin: 10px 20px;
+}
+
+.c-left iframe,.c-left img{
+  width: 100%;
+  min-height: 70vh;
+}
+
+.c-right{
+  flex: 1;
+  .c-h1{
+    color: #B63C25;
+    font-size: 1.25rem;
+    font-weight: bold;
+  }
+}
+
+.c-right .c-title{
+  font-weight: bold;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px solid #532F1C;
+  color: #532F1C;
+  font-size: 1.125rem;
+}
+
+.edit{
+  cursor: pointer;
+}
+.c-right p{
+  margin: 40px 20px 40px 0;
+  word-break: break-all;
+  line-height: 1.5;
+  font-size: 1rem;
+}
+.con-btn{
+  padding-right: 1.25rem;
+}
+
+.media-cls{
+  color: rgba(0, 176, 255, 1);
+  cursor: pointer;
+  margin-top: 20px;
+  p{
+    line-height: 2;
+    margin: 0;
+  }
+}
+
+.iconfont{
+  cursor: pointer;
+}
+
+.dialog{
+  .content{
+    border: .0625rem solid #ccc;
+    padding: .625rem;
+    margin: .625rem auto;
+    div,li{
+      line-height: 2;
+    }
+  }
+  .textarea{
+    padding: 0;
+    border: none;
+  }
+}
+
+</style>
+
+<style>
+.ql-picker-label {
+  line-height: 1;
+  overflow: hidden;
+}
+
+.avatar-uploader .el-upload {
+  border: 1px dashed #000;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+.iconfont{
+  font-size: 20px;
+}
+
+</style>

+ 150 - 0
src/pages/survey/surveyList.vue

@@ -0,0 +1,150 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData">
+      <div slot="con"></div>
+    </main-top>
+    <div class="table-interface">
+      <div class="top-body" style="padding: 50px 20px">
+        <el-form
+          :model="form"
+          :rules="rules"
+          ref="form"
+          label-width="100px"
+          class="demo-ruleForm"
+        >
+          <el-row>
+            <el-col :span="12">
+              <el-form-item label="类别" prop="type">
+                <el-select v-model="form.type" placeholder="请选择类别">
+                  <el-option label="本馆介绍" value="introduce"></el-option>
+                  <el-option label="历史革命" value="history"></el-option>
+                  <el-option label="机构职能" value="organ"></el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row>
+            <el-col :span="14">
+              <el-form-item label="内容" prop="content">
+                <vue-editor
+                  class="quill-editor"
+                  v-model="form.content"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-form-item>
+            <el-button type="primary" @click="submitForm('form')"
+              >保存</el-button
+            >
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+const crumbData = [
+  {
+    name: "概况编辑",
+    id: 3,
+  },
+];
+import MainTop from "@/components/main-top";
+import * as common from "@/util/commonfn.js";
+import { VueEditor } from "vue2-editor";
+export default {
+  components: {
+    MainTop,
+    VueEditor,
+  },
+  data() {
+    return {
+      crumbData,
+      form: {
+        type:'introduce'
+      },
+      rules: {
+        type: [{ required: true, message: "请选择类别", trigger: "blur" }],
+        content: [{ required: true, message: "请输入内容", trigger: "blur" }],
+      },
+      token: window.localStorage.getItem("token")
+    };
+  },
+  computed: {},
+  watch: {
+    'form.type':{
+      handler:function() {
+        this.getDetail();
+      }
+    }
+  },
+  mounted() {},
+  created() {
+    this.getDetail();
+  },
+  methods: {
+    async getDetail() {
+      let result = await this.$http({
+        method: "post",
+        url: `/manage/profile/list/${this.form.type}`
+      });
+      if (result["code"] === 0) {
+        this["form"] = result["data"];
+      } else {
+        this["form"] = {};
+      }
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.save();
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    async save() {
+      let data = this["form"];
+      let result = await this.$http({
+        method: "post",
+        data,
+        url: "/manage/profile/save",
+      });
+      if (result["code"] === 0) {
+        common.tip("success", "保存成功");
+        this.getDetail();
+      } else {
+        common.tip("error", "保存失败,请联系管理员");
+      }
+    },
+  },
+};
+</script>
+
+<style scoped>
+.table-interface {
+  height: calc(100% - 3rem);
+  overflow: auto;
+}
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+.info-top {
+  padding: 20px 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px #a5a5a5 solid;
+}
+</style>

+ 485 - 0
src/pages/system/Download.vue

@@ -0,0 +1,485 @@
+<!--  -->
+<template>
+  <div>
+    <main-top :crumb="crumbData"></main-top>
+    <div class="table-interface">
+      <div class="top-body">
+        <div class="info-top">
+          <div class="info-left">
+            <span>按功能模块查看:</span>
+            <el-select v-model="typeId" placeholder="请选择">
+              <el-option label="全部" value></el-option>
+              <el-option v-for="(item, i) in typeArr" :key="i" :label="item.name" :value="item.id"></el-option>
+            </el-select>
+            <span style="margin-left:20px;">按状态查看:</span>
+            <el-select v-model="statusId" placeholder="请选择">
+              <el-option label="全部" value></el-option>
+              <el-option
+                v-for="(item, i) in statusArr"
+                :key="i"
+                :label="item.name"
+                :value="item.id"
+              ></el-option>
+            </el-select>
+            <el-input style="width:220px;margin:0 20px;" v-model="inputKey" placeholder="请输入关键字搜索"></el-input>
+            <el-button type="primary" @click="getInformation">查找</el-button>
+            <el-button @click="reset">重置</el-button>
+          </div>
+          <!-- <div class="info-right">
+            <el-button type="primary" @click="$router.push({name:'edit-parts',params:{type:0,id:'none'}})">新增文物</el-button>
+          </div>-->
+        </div>
+        <el-table :data="tableData" style="width: 100%">
+          <el-table-column
+            v-for="(item, idx) in data"
+            :key="idx"
+            :prop="item.prop"
+            :label="item.label"
+          >
+            <template slot-scope="scope">
+              <span>{{ scope.row[item.prop] || "-" }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <span @click="show(scope.row)" class="o-span">查看详情</span>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="e-pagination">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page.sync="currentPage"
+            :page-size="size"
+:page-sizes="PAGESIZES"
+            layout="prev, pager, next, jumper"
+            :total="total"
+          ></el-pagination>
+        </div>
+
+        <el-dialog title="审核申请内容" :visible.sync="dialogFormVisible" width="40%">
+          <div class="add-con">
+            <h2 v-if="form.status!==1">你的申请{{statusStr[form.status]}}!</h2>
+
+            <el-form :model="form">
+              <el-form-item label="申请人:" :label-width="formLabelWidth">
+                <span>{{ form.userName || "-" }}</span>
+              </el-form-item>
+              <el-form-item label="申请时间:" :label-width="formLabelWidth">
+                <span>{{ form.createTime || "-" }}</span>
+              </el-form-item>
+              <el-form-item label="申请原因:" :label-width="formLabelWidth">
+                <span>{{ form.reason || "-" }}</span>
+              </el-form-item>
+            </el-form>
+            <template v-if="form.status !== 3||$role=='admin'">
+               <div class="file_cls">申请下载的内容:</div>
+                <ul class="file_ul">
+                  <el-checkbox-group v-model="checkList" @change='handleChange'>
+                    <div style="line-height:2" v-for="(sub,idx) in files" :key="idx">
+                      <el-checkbox :label="sub.id" :false-label="''" :true-label="''">{{sub.fileName}}</el-checkbox>
+                    </div>
+                  </el-checkbox-group>
+                  
+                  <el-button v-if="form.status !== 1||$role=='admin'" size="mini" style="margin-top:20px" @click="downLoad" type="primary">下载</el-button>
+                </ul>
+            </template>
+          </div>
+          <div slot="footer" class="dialog-footer" v-if="$role=='admin'" >
+            <el-button type="primary" @click="shenHe(2)">{{form.status === 1?'同 意':'确 定'}}</el-button>
+            <el-button @click="shenHe(3)">{{form.status === 1?'驳 回':'返 回'}}</el-button>
+          </div>
+        </el-dialog>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+
+import MainTop from "@/components/main-top";
+const crumbData = [
+  {
+    name: "下载管理",
+    id: 5
+  }
+];
+
+const TYPENAME = {
+  part: "部件信息管理",
+  building: "建筑物信息管理"
+};
+
+const STATUSNAME = {
+  1: "待审核",
+  2: "已同意",
+  3: "已驳回"
+};
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    MainTop
+  },
+  data() {
+    // 这里存放数据
+    let data = [
+      {
+        prop: "idx",
+        label: "序号"
+      },
+      {
+        prop: "typeName",
+        label: "资料所属模块"
+      },
+      {
+        prop: "name",
+        label: "部件/建筑物名称"
+      },
+      {
+        prop: "userName",
+        label: "申请人"
+      },
+      {
+        prop: "createTime",
+        label: "申请时间"
+      },
+      {
+        prop: "statusStr",
+        label: "当前状态"
+      }
+    ];
+
+    const statusArr = [
+      {
+        id: 1,
+        name: "待审核"
+      },
+      {
+        id: 2,
+        name: "已同意"
+      },
+      {
+        id: 3,
+        name: "已驳回"
+      }
+    ];
+
+    const statusStr =       {
+        2: "已同意",
+        3: "已驳回",
+      }
+    ;
+
+    const typeArr = [
+      {
+        id: "part",
+        name: "部件信息管理"
+      },
+      {
+        id: "building",
+        name: "建筑物信息管理"
+      }
+    ];
+    return {
+      crumbData,
+      data,
+      checkList:[],
+      infoName: "",
+      currentPage: 1,
+      dialogFormVisible: false,
+      size: 25,
+      total: 0,
+      tableData: [],
+      statusArr,
+      typeArr,
+      statusStr,
+      statusId: "",
+      typeId: "",
+      inputKey: "",
+      form: {
+        createTime: "",
+        fileIds: "",
+        id: 0,
+        name: "",
+        reason: "",
+        status: 0,
+        type: "",
+        updateTime: "",
+        userName: ""
+      },
+      formLabelWidth: "120px",
+      files:[]
+    };
+  },
+  watch: {
+    currentPage() {
+      this.refresh();
+    },
+    size() {
+      this.refresh();
+    }
+  },
+  mounted() {
+    this.refresh();
+  },
+  methods: {
+    handleChange(){},
+    async downLoad(){
+      if (!this.checkList.length) {
+        return this.$alert("请勾选下载内容", "提示", {
+            confirmButtonText: "确定",
+            callback: () => {
+              return
+            },
+        })
+      }
+      // let loading = this.$loading({
+      //   lock: true,
+      //   text: 'Loading',
+      //   spinner: 'el-icon-loading',
+      //   background: 'rgba(0, 0, 0, 0.7)'
+      // });
+      let result = await this.$http({
+        method: "get",
+        headers: {
+          token: window.localStorage.getItem("token")
+        },
+        url: `/manage/download/download/${this.checkList.join(',')}`
+      });
+      // loading.close()
+
+      if (result.code === 0) {
+        window.location.href = result.msg
+      } else {
+        this.$notify.error({
+          title: "错误",
+          message: '下载失败'
+        });
+      }
+    },
+    async shenHe(status = 3) {
+      if (this.form.status!==1) {
+        return this.dialogFormVisible = false
+      }
+      let result = await this.$http({
+        method: "get",
+        headers: {
+          token: window.localStorage.getItem("token")
+        },
+        url: `/manage/download/audit/${this.form.id}/${status}`
+      });
+
+      if (result.code === 0) {
+        this.$alert("审核成功", "提示", {
+          confirmButtonText: "确定",
+          callback: () => {
+            this.refresh();
+          }
+        });
+      } else {
+        this.$notify.error({
+          title: "错误",
+          message: result.msg
+        });
+      }
+    },
+    refresh() {
+      this.dialogFormVisible = false;
+      this.loading = true;
+      this.getInformation();
+      this.loading = false;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+    },
+    reset() {
+      this.inputKey = "";
+      this.statusId = "";
+      this.typeId = ""
+    },
+
+    async getDetail(id){
+      let result = await this.$http({
+        method: 'get',
+        headers: {
+          token: window.localStorage.getItem('token')
+        },
+        url: `/manage/download/detail/${id}`
+      })
+
+      this.form = result.data.obj
+      this.files = result.data.file
+    },
+
+    show(item = {}) {
+      this.dialogFormVisible = true;
+      this.checkList = []
+      this.getDetail(item.id)
+    },
+
+    async getInformation() {
+      let params = {
+        pageNum: this.currentPage,
+        pageSize: this.size,
+        searchKey: this.inputKey,
+        type:this.typeId,
+        status:this.statusId
+      };
+
+      let result = await this.$http({
+        method: "post",
+        data: params,
+        headers: {
+          token: window.localStorage.getItem("token")
+        },
+        url: "/manage/download/list"
+      });
+
+      if (result.code !== 0) {
+        return;
+      }
+      this.tableData = result.data.list;
+      this.total = result.data.total;
+      this.tableData.forEach((item, i) => {
+        item["idx"] = i + 1;
+        item["typeName"] = TYPENAME[item.type];
+        item["statusStr"] = STATUSNAME[item.status];
+      });
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+.top-body {
+  border-top: 0.0625rem solid #e6e6e6;
+  line-height: 1.5;
+  padding: 0 1.25rem 1.25rem;
+  align-items: center;
+  box-sizing: border-box;
+  background: #fff;
+  margin: 1rem 0;
+}
+
+.top-body .top-con {
+  font-weight: bold;
+}
+.table-title {
+  padding: 1rem 1rem 1rem 0;
+  font-size: 1rem;
+  color: #2d2d2d;
+  border-bottom: 1px solid #ccc;
+  display: flex;
+  justify-content: space-between;
+}
+
+.more {
+  color: #ec652d;
+  cursor: pointer;
+}
+.add-con{
+  h2{
+    text-align: center;
+    font-size: 20px;
+    margin-bottom: 30px;
+  }
+}
+.top-right {
+  background-color: #ec652d;
+  height: 3.5625rem;
+  line-height: 3.5625rem;
+  color: #fff;
+  padding: 0 1.875rem;
+  border-radius: 0.3125rem;
+  font-size: 1.125rem;
+  font-weight: bold;
+}
+
+.search-body {
+  background-color: #fff;
+  margin: 1.25rem 0;
+}
+
+.interface-table {
+  height: calc(100% - 17.1875rem);
+  overflow-x: hidden;
+  background-color: #fff;
+  padding: 0 1.125rem 2.375rem;
+  box-sizing: border-box;
+}
+
+.file_cls{
+  padding-left: 38px;  
+  margin-bottom: 20px;
+}
+
+.file_ul{
+  border: 1px solid #ccc;
+  padding: 20px 40px;  
+  margin-bottom: 20px;
+}
+
+.file_ul li{
+  color: #409eff;
+  margin-bottom: 6px;
+  cursor: pointer;
+}
+
+.zan-con {
+  display: flex;
+  width: 100%;
+  justify-content: space-around;
+  margin-top: 1.5rem;
+  text-align: center;
+  font-size: 1.125rem;
+}
+
+.zan-con .line {
+  height: 8rem;
+  width: 1px;
+  background: #ccc;
+}
+
+.zan-con .zan-contain {
+  display: flex;
+  justify-content: space-between;
+  flex-direction: column;
+}
+
+.zan-con .zan-contain p {
+  font-size: 2.25rem;
+}
+
+.zan-con .zan-contain p:first-child {
+  font-size: 0.875rem;
+  line-height: 1.5;
+}
+
+.zan-sub {
+  text-align: right;
+  margin-top: 1.25rem;
+  color: #a5a5a5;
+  font-size: 0.875rem;
+}
+
+.table-interface {
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: calc(100% - 3rem);
+}
+
+.info-top {
+  padding: 20px 0;
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px #a5a5a5 solid;
+}
+
+.o-span {
+  cursor: pointer;
+  color: rgb(7, 152, 244);
+}
+</style>

+ 0 - 0
src/pages/system/Menu.vue


Some files were not shown because too many files changed in this diff