xionghaojie vor 3 Jahren
Ursprung
Commit
0c722d0f77
38 geänderte Dateien mit 3692 neuen und 123 gelöschten Zeilen
  1. 102 7
      package-lock.json
  2. 8 2
      package.json
  3. BIN
      public/favicon.ico
  4. 872 16
      src/App.vue
  5. BIN
      src/assets/images/check_gou.png
  6. BIN
      src/assets/images/defaultimg.jpg
  7. BIN
      src/assets/images/kefu.png
  8. BIN
      src/assets/images/kefu2.png
  9. BIN
      src/assets/images/l-baomingbiao.png
  10. BIN
      src/assets/images/l-kefu.png
  11. BIN
      src/assets/images/l-lunbo.png
  12. BIN
      src/assets/images/l-shangping.png
  13. BIN
      src/assets/images/l-tupian.png
  14. BIN
      src/assets/images/l-wenbeng.png
  15. BIN
      src/assets/images/resouceNone.png
  16. BIN
      src/assets/images/topNavBlack.png
  17. 0 59
      src/components/HelloWorld.vue
  18. 121 0
      src/components/View/editorApplicationForm.vue
  19. 48 0
      src/components/View/editorBanner.vue
  20. 37 0
      src/components/View/editorCustomerService.vue
  21. 25 0
      src/components/View/editorImage.vue
  22. 200 0
      src/components/View/editorProduct.vue
  23. 40 0
      src/components/View/editorText.vue
  24. 471 0
      src/components/materialManage.vue
  25. 445 0
      src/components/productManage.vue
  26. 298 0
      src/components/setting/settingApplicationForm.vue
  27. 197 0
      src/components/setting/settingBanner.vue
  28. 125 0
      src/components/setting/settingCustomerService.vue
  29. 120 0
      src/components/setting/settingImage.vue
  30. 362 0
      src/components/setting/settingProduct.vue
  31. 101 0
      src/components/setting/settingText.vue
  32. 5 1
      src/main.js
  33. 13 14
      src/router/index.js
  34. 63 0
      src/utlis/axios.js
  35. 23 0
      src/utlis/utli.js
  36. 0 5
      src/views/AboutView.vue
  37. 0 18
      src/views/HomeView.vue
  38. 16 1
      vue.config.js

+ 102 - 7
package-lock.json

@@ -2367,6 +2367,19 @@
         "lodash": "^4.17.14"
       }
     },
+    "async-validator": {
+      "version": "1.8.5",
+      "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-1.8.5.tgz",
+      "integrity": "sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==",
+      "requires": {
+        "babel-runtime": "6.x"
+      }
+    },
+    "asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+    },
     "at-least-node": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz",
@@ -2387,6 +2400,20 @@
         "postcss-value-parser": "^4.2.0"
       }
     },
+    "axios": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmmirror.com/axios/-/axios-0.27.2.tgz",
+      "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+      "requires": {
+        "follow-redirects": "^1.14.9",
+        "form-data": "^4.0.0"
+      }
+    },
+    "babel-helper-vue-jsx-merge-props": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmmirror.com/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz",
+      "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg=="
+    },
     "babel-loader": {
       "version": "8.2.5",
       "resolved": "https://registry.npmmirror.com/babel-loader/-/babel-loader-8.2.5.tgz",
@@ -2438,6 +2465,27 @@
         "@babel/helper-define-polyfill-provider": "^0.3.2"
       }
     },
+    "babel-runtime": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmmirror.com/babel-runtime/-/babel-runtime-6.26.0.tgz",
+      "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
+      "requires": {
+        "core-js": "^2.4.0",
+        "regenerator-runtime": "^0.11.0"
+      },
+      "dependencies": {
+        "core-js": {
+          "version": "2.6.12",
+          "resolved": "https://registry.npmmirror.com/core-js/-/core-js-2.6.12.tgz",
+          "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
+        },
+        "regenerator-runtime": {
+          "version": "0.11.1",
+          "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+          "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
+        }
+      }
+    },
     "balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -2854,6 +2902,14 @@
       "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
       "dev": true
     },
+    "combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "requires": {
+        "delayed-stream": "~1.0.0"
+      }
+    },
     "commander": {
       "version": "2.20.3",
       "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz",
@@ -3271,8 +3327,7 @@
     "deepmerge": {
       "version": "1.5.2",
       "resolved": "https://registry.npmmirror.com/deepmerge/-/deepmerge-1.5.2.tgz",
-      "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==",
-      "dev": true
+      "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ=="
     },
     "default-gateway": {
       "version": "6.0.3",
@@ -3389,6 +3444,11 @@
         "object-keys": "^1.1.1"
       }
     },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
+    },
     "depd": {
       "version": "2.0.0",
       "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz",
@@ -3523,6 +3583,19 @@
       "integrity": "sha512-BZSbMpyFQU0KBJ1JG26XGeFI3i4op+qOYGxftmZXFZoHkhLgsSv4DHDJfl8ogII3hIuzGt51PaZ195OVu0yJ9A==",
       "dev": true
     },
+    "element-ui": {
+      "version": "2.15.9",
+      "resolved": "https://registry.npmmirror.com/element-ui/-/element-ui-2.15.9.tgz",
+      "integrity": "sha512-dx45nQLt4Hn87/Z9eRr3ex6KFZbxlFAwEU3QoW3wA5EsYftvHTyL9Pq7VnXXD7hu1Eiaup2jcs6kp+/VSFmXuA==",
+      "requires": {
+        "async-validator": "~1.8.1",
+        "babel-helper-vue-jsx-merge-props": "^2.0.0",
+        "deepmerge": "^1.2.0",
+        "normalize-wheel": "^1.0.1",
+        "resize-observer-polyfill": "^1.5.0",
+        "throttle-debounce": "^1.0.1"
+      }
+    },
     "emoji-regex": {
       "version": "8.0.0",
       "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -3882,8 +3955,17 @@
     "follow-redirects": {
       "version": "1.15.1",
       "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.1.tgz",
-      "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
-      "dev": true
+      "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
+    },
+    "form-data": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz",
+      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+      "requires": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      }
     },
     "forwarded": {
       "version": "0.2.0",
@@ -4899,14 +4981,12 @@
     "mime-db": {
       "version": "1.52.0",
       "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
-      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
-      "dev": true
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
     },
     "mime-types": {
       "version": "2.1.35",
       "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
       "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
-      "dev": true,
       "requires": {
         "mime-db": "1.52.0"
       }
@@ -5137,6 +5217,11 @@
       "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
       "dev": true
     },
+    "normalize-wheel": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/normalize-wheel/-/normalize-wheel-1.0.1.tgz",
+      "integrity": "sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA=="
+    },
     "npm-run-path": {
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-2.0.2.tgz",
@@ -6105,6 +6190,11 @@
       "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
       "dev": true
     },
+    "resize-observer-polyfill": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
+      "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
+    },
     "resolve": {
       "version": "1.22.1",
       "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz",
@@ -6740,6 +6830,11 @@
         }
       }
     },
+    "throttle-debounce": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/throttle-debounce/-/throttle-debounce-1.1.0.tgz",
+      "integrity": "sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg=="
+    },
     "thunky": {
       "version": "1.1.0",
       "resolved": "https://registry.npmmirror.com/thunky/-/thunky-1.1.0.tgz",

+ 8 - 2
package.json

@@ -4,10 +4,16 @@
   "private": true,
   "scripts": {
     "serve": "vue-cli-service serve",
-    "build": "vue-cli-service build"
+    "build": "vue-cli-service build",
+    "dev": "vue-cli-service serve --mode dev",
+    "dev:test": "vue-cli-service serve --mode testenv",
+    "build:dev": "vue-cli-service build --mode dev",
+    "build:test": "vue-cli-service build --mode testenv"
   },
   "dependencies": {
+    "axios": "^0.27.2",
     "core-js": "^3.8.3",
+    "element-ui": "^2.15.9",
     "vue": "^2.6.14",
     "vue-router": "^3.5.1",
     "vuex": "^3.6.2"
@@ -26,4 +32,4 @@
     "last 2 versions",
     "not dead"
   ]
-}
+}

BIN
public/favicon.ico


+ 872 - 16
src/App.vue

@@ -1,14 +1,541 @@
 <template>
-  <div id="app">
-    <nav>
-      <router-link to="/">Home</router-link> |
-      <router-link to="/about">About</router-link>
-    </nav>
-    <router-view/>
+  <div>
+    <div class="header">
+      <!-- <img src="/statics/image/loginLogo.png" class="logo" alt="华讯时代" style="height: 26px;width: 184px"/> -->
+      <div class="tplName">
+        <label>
+          <input v-model="viewTitle" placeholder="请输入标题名称" type="text" />
+        </label>
+        <i class="el-icon-edit"></i>
+      </div>
+      <div class="button-group">
+        <!--            <el-button type="primary" @click="previewAdvert" size="mini">预览</el-button>-->
+        <!-- <el-button type="primary" @click="lookJson" size="mini">查看JSON</el-button> -->
+        <el-button type="primary" @click="submit" size="mini">提交页面</el-button>
+        <el-button size="mini" @click="closeOpenWindows">关闭</el-button>
+      </div>
+      <div class="editor">
+      </div>
+    </div>
+    <section class="decoration-edit">
+      <section class="l">
+        <div class="title">封面图片</div>
+        <div>
+          <div class="cover">
+            <img v-if="pic" :src="pic" />
+            <img v-else src="@/assets/images/defaultimg.jpg" />
+          </div>
+          <!-- 上传图片 -->
+          <div class="updataBtn">
+            <el-button style="width:100%" type="primary" size="mini" @click="updataImage">上传封面</el-button>
+          </div>
+        </div>
+        <ul>
+          <div class="title">组件选择</div>
+          <li v-for="(val, index) in typeList" :key="index + 1" @click="clickType(val)">
+            <img :src="require('./assets/images/' + val.icon)">
+            <!-- <img src="./assets/images/l-kefu.png"> -->
+            <!-- <span :class="val.icon"></span> -->
+            <p>{{ val.name }}</p>
+          </li>
+        </ul>
+      </section>
+
+      <section class="c">
+        <div class="top-nav">
+          <img src="./assets/images/topNavBlack.png">
+          <span class="tit">{{ viewTitle }}</span>
+        </div>
+        <div class="view-content">
+          <div v-for="(item, index) in view" :key="index">
+            <div v-if="!item.isHover" :data-index="index" :key="index" class="item" @click="selectType(item)">
+              <component :is="item.com" :data="item" :key="index + '_'"></component>
+              <i @click="deleteItem($event, index)" class="el-icon-error"></i>
+              <div class="control-tool-bar">
+                <el-tooltip class="item" effect="light" content="上移" placement="bottom">
+                  <el-button class="ctrl-icon icon-up" type="text" size="small" @click.stop="upItem(item)"
+                    :disabled="index == 0"></el-button>
+                </el-tooltip>
+                <el-tooltip class="item" effect="light" content="下移" placement="bottom">
+                  <el-button class="ctrl-icon icon-down" type="text" size="small" @click.stop="downItem(item)"
+                    :disabled="index == view.length - getHoverList().length - 1"></el-button>
+                </el-tooltip>
+              </div>
+            </div>
+            <div v-if="item.isHover" :data-index="index" :key="index" class="item nobackground" :class="item.position"
+              :style="'width:' + (item.width ? item.width : 100) + 'px;height:' + (item.height ? item.height : 100) + 'px;'"
+              @click="selectType(item)">
+              <component :is="item.com" :data="item" :key="index + '_'"></component>
+              <i @click="deleteItem($event, index)" class="el-icon-error"></i>
+            </div>
+          </div>
+        </div>
+      </section>
+
+      <section class="r" :class="isRight ? '' : 'nobackground'">
+        <component v-if="isRight" :is="propsData.setCom" :data="propsData"
+          @closeRightTemplateHandle="closeRightTemplateHandle" @updataContent="updataContent"></component>
+      </section>
+
+      <!-- <div class="submit-btn">
+        <el-button @click="submit">提交页面</el-button>
+      </div> -->
+    </section>
+
+    <materialManage v-if="materialVisible" :on-success="chooseImageHandle" :file-type="1" item-or-src="item">
+    </materialManage>
   </div>
 </template>
 
-<style lang="scss">
+
+<script>
+import service from './utlis/axios'
+import { setCookie, getCookie, clearCookie } from '@/utlis/utli'
+import materialManage from './components/materialManage.vue'
+import editorImage from '@/components/View/editorImage'
+import settingImage from '@/components/setting/settingImage'
+import editorBanner from '@/components/View/editorBanner'
+import settingBanner from '@/components/setting/settingBanner'
+import editorText from '@/components/View/editorText'
+import settingText from '@/components/setting/settingText'
+import editorApplicationForm from '@/components/View/editorApplicationForm'
+import settingApplicationForm from '@/components/setting/settingApplicationForm'
+import editorCustomerService from '@/components/View/editorCustomerService'
+import settingCustomerService from '@/components/setting/settingCustomerService'
+import editorProduct from '@/components/View/editorProduct'
+import settingProduct from '@/components/setting/settingProduct'
+export default {
+  components: {
+    editorImage,
+    editorBanner,
+    settingImage,
+    settingBanner,
+    editorText,
+    settingText,
+    editorApplicationForm,
+    settingApplicationForm,
+    editorCustomerService,
+    settingCustomerService,
+    editorProduct,
+    settingProduct,
+    materialManage
+  },
+  data() {
+    return {
+      pic: '',//封面
+      typeList: [
+        {
+          name: '轮播图',
+          key: 'banner',
+          icon: 'l-lunbo.png',
+          com: 'editorBanner',
+          setCom: 'settingBanner',
+          value: {
+            imageList: [{ src: '' }]
+          }
+        }, {
+          name: '图片',
+          key: 'images',
+          icon: 'l-tupian.png',
+          com: 'editorImage',
+          setCom: 'settingImage',
+          value: {
+            src: ''
+          }
+        }, {
+          name: '文本',
+          key: 'text',
+          icon: 'l-wenbeng.png',
+          com: 'editorText',
+          setCom: 'settingText',
+          value: {
+            content: '',
+            isTitle: false
+          }
+        }, {
+          name: '报名表',
+          key: 'applicationForm',
+          icon: 'l-baomingbiao.png',
+          com: 'editorApplicationForm',
+          setCom: 'settingApplicationForm',
+          value: {
+            title: { value: '报名表', isShow: true },
+            database: '',
+            formItemList: [{
+              label: '', databaseLabel: '', type: 1, required: true
+            }, {
+              label: '', databaseLabel: '', type: 1, required: true
+            }, {
+              label: '', databaseLabel: '', type: 5, required: true, option: [{ label: '', value: '' }, { label: '', value: '' }]
+            }],
+            buttonName: ''
+          }
+        }, {
+          name: '客服',
+          key: 'customerService',
+          icon: 'l-kefu.png',
+          com: 'editorCustomerService',
+          setCom: 'settingCustomerService',
+          isHover: true,
+          position: 'right-bottom',//left-top
+          width: '70',
+          height: '70',
+          value: {
+            type: '',
+            text: ''
+          }
+        }, {
+          name: '商品',
+          key: 'product',
+          icon: 'l-shangping.png',
+          com: 'editorProduct',
+          setCom: 'settingProduct',
+          value: {
+            layoutNum: 1,
+            productList: [],
+            showOriginalPrice: false
+          }
+        }],
+      view: [],
+      type: '',
+      propsData: {},
+      isRight: false,
+      materialVisible: false,
+      pass: true,//校验
+      id: null,
+      libraryExtendId: null,
+      viewTitle: '',
+      bindId: null,
+      bindType: null
+    }
+  },
+  computed: {
+    info() {
+      return this.view[0]
+    }
+  },
+  created() {
+    var sid = this.getUrlParamValue('sid');
+    sessionStorage.setItem('shiro.sesssion', sid)
+    if (sid) {
+      setCookie('shiro.sesssion', sid, 1)
+    } else {
+      setCookie('shiro.sesssion', "", -1);
+    }
+
+    // 编辑
+    var id = this.getUrlParamValue('id');
+    var bindId = this.getUrlParamValue('bindId');
+    var bindType = this.getUrlParamValue('bindType');
+    this.id = id
+    this.bindId = bindId
+    this.bindType = bindType
+    if (id) {
+      this.getMaterialLibrary(id)
+    } else if (bindId) {
+      this.getMaterialLibraryByBindId(bindId, bindType)
+    }
+  },
+  methods: {
+    // 关闭窗口
+    closeOpenWindows() {
+      window.open("about:blank", "_top").close();
+    },
+    getImage(url) {
+      return require(url)
+    },
+    // 上传图片
+    updataImage() {
+      this.materialVisible = true
+    },
+    // 选择图片
+    chooseImageHandle(val) {
+      this.pic = val.url
+      this.materialVisible = false
+    },
+    getUrlParamValue(name) {
+      var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
+      var r = window.location.search.substr(1).match(reg);
+      if (r != null) return unescape(r[2]);
+      return null;
+    },
+    // 编辑,根据id查询
+    getMaterialLibrary(id) {
+      service.get("/material/library/" + id).then((res) => {
+        if (res.data.data) {
+          this.pic = res.data.data.pic
+          this.view = JSON.parse(res.data.data.libraryExtend.params)
+          this.id = res.data.data.id
+          this.libraryExtendId = res.data.data.libraryExtend.id
+          this.viewTitle = res.data.data.title
+        }
+      }).catch(function () {
+
+      });
+    },
+    getMaterialLibraryByBindId(bindId, bindType) {
+      service.get(`/material/library/info?bindId=${bindId}&bindType=${bindType}`).then((res) => {
+        if (res.data.data) {
+          this.pic = res.data.data.pic
+          this.view = JSON.parse(res.data.data.libraryExtend.params)
+          this.id = res.data.data.id
+          this.libraryExtendId = res.data.data.libraryExtend.id
+          this.viewTitle = res.data.data.title
+        }
+      }).catch(() => {
+      });
+    },
+    // index排序
+    position() {
+      let commonList = this.view.filter((item) => { return item.isHover != true })
+      let hoverList = this.view.filter((item) => { return item.isHover == true })
+      this.view = [...commonList, ...hoverList]
+      this.view.forEach((item, index) => {
+        item.index = index
+      })
+    },
+    getHoverList() {
+      return this.view.filter((item) => { return item.isHover == true })
+    },
+    clickType(val) {
+      this.view.push(JSON.parse(JSON.stringify(val)))
+      this.position()
+    },
+    deleteItem(e, index) {
+      e.preventDefault()
+      e.stopPropagation()
+      this.view.splice(index, 1)
+      this.isRight = false
+      this.propsData = {}
+      this.position()
+    },
+    selectType(val) {
+      this.isRight = false
+      this.propsData = val
+      this.$nextTick(() => this.isRight = true)
+    },
+    closeRightTemplateHandle(val) {
+      this.isRight = val
+    },
+    updataContent(val) {
+      this.$set(this.view, val.index, JSON.parse(JSON.stringify(val)))
+      // this.view.forEach(item => {
+      //   if(item.key==val.key&&item.index==val.index) item = JSON.parse(JSON.stringify(val))
+      // });
+    },
+    lookJson() {
+      this.$alert(JSON.stringify(this.view), 'JSON', {
+        confirmButtonText: '确定'
+      });
+    },
+    // 上移
+    upItem(item) {
+      if (item.index == 0) return
+      if (this.view[item.index - 1].isHover) {
+        this.swapArray(this.view, item.index - 2, item.index);
+      } else {
+        this.swapArray(this.view, item.index - 1, item.index);
+      }
+      this.$nextTick(() => {
+        this.selectType(item);
+      })
+    },
+    // 下移
+    downItem(item) {
+      if (item.index == this.view.length) return
+      if (this.view[item.index + 1].isHover) {
+        this.swapArray(this.view, item.index, item.index + 2);
+      } else {
+        this.swapArray(this.view, item.index, item.index + 1);
+      }
+      this.$nextTick(() => {
+        this.selectType(item);
+      })
+    },
+    //数组元素互换位置
+    swapArray(arr, index1, index2) {
+      arr[index1] = arr.splice(index2, 1, arr[index1])[0];
+      this.position()
+      return arr;
+    },
+    // 提交
+    submit() {
+      this.checkSubmit()
+      if (this.pass) {
+        let posObj = {
+          pic: this.pic,
+          libraryExtend: {
+            params: JSON.stringify(this.view)
+          },
+          title: this.viewTitle,
+          rootCode: 'brochure'
+        }
+        if (this.id) {
+          posObj.id = this.id
+          posObj.libraryExtend.id = this.libraryExtendId
+          service.put("/material/library", posObj).then((res) => {
+            this.$message.success('编辑成功')
+          }).catch(function () {
+
+          });
+        }else {
+          if (this.bindId) {
+            posObj.bindId = this.bindId
+            posObj.bindType = this.bindType
+          }
+          service.post("/material/library", posObj).then((res) => {
+            if (res.data.data.code)
+              this.$message.success('提交成功')
+          }).catch(function () {
+
+          });
+        }
+      } else {
+
+      }
+    },
+    // 校验
+    checkSubmit() {
+      let that = this
+      that.pass = true
+      if (this.view.length == 0) {
+        that.pass = false
+        return this.$message.error("请添加组件");
+      }
+      if (!this.pic || this.pic == '') {
+        that.pass = false
+        return this.$message.error("请上传封面");
+      }
+      if (!this.viewTitle || this.viewTitle == '') {
+        that.pass = false
+        return this.$message.error("请填写标题");
+      }
+      this.view.forEach(item => {
+        if (!that.pass) return
+        switch (item.key) {
+          case 'banner':
+            {
+              item.value.imageList.forEach((src) => {
+                if (!src.src || src.src == '') {
+                  that.pass = false
+                  this.selectType(item)
+                  return this.$message.error("请选择banner图图片");
+                }
+              })
+            }
+            break;
+          case 'images':
+            {
+              if (!item.value.src || item.value.src == '') {
+                that.pass = false
+                this.selectType(item)
+                return this.$message.error("请选择图片");
+              }
+            }
+            break;
+          case 'text':
+            {
+              if (!item.value.content || item.value.content == '') {
+                that.pass = false
+                this.selectType(item)
+                return this.$message.error("文本不能为空");
+              }
+            }
+            break;
+          case 'applicationForm':
+            {
+              if (item.value.title.isShow && (!item.value.title.value || item.value.title.value == '')) {
+                that.pass = false
+                this.selectType(item)
+                return this.$message.error("已开启显示标题,标题不能为空");
+              } else if (!item.value.database || item.value.database == '') {
+                that.pass = false
+                this.selectType(item)
+                return this.$message.error("表单数据库名不能为空");
+              } else if (!item.value.buttonName || item.value.buttonName == '') {
+                that.pass = false
+                this.selectType(item)
+                return this.$message.error("表单按钮名称不能为空");
+              } else if (item.value.formItemList) {
+                item.value.formItemList.forEach(sitem => {
+                  if (!that.pass) return
+                  if (!sitem.label || sitem.label == '') {
+                    that.pass = false
+                    this.selectType(item)
+                    return this.$message.error("表单字段名不能为空");
+                  } else if (!sitem.databaseLabel || sitem.databaseLabel == '') {
+                    that.pass = false
+                    this.selectType(item)
+                    return this.$message.error("表单数据库字段名不能为空");
+                  } else if (sitem.type == 'select') {
+                    if (!sitem.option) {
+                      that.pass = false
+                      this.selectType(item)
+                      return this.$message.error("表单下拉框选项不能为空");
+                    } else {
+                      sitem.option.forEach(ssitem => {
+                        if (!ssitem.label || ssitem.label == '') {
+                          that.pass = false
+                          this.selectType(item)
+                          return this.$message.error("表单下拉框选项标签不能为空");
+                        } else if (!ssitem.value || ssitem.value == '') {
+                          that.pass = false
+                          this.selectType(item)
+                          return this.$message.error("表单下拉框选项值不能为空");
+                        }
+                      })
+                    }
+                  }
+                })
+              }
+            }
+            break;
+          case 'customerService':
+            {
+              if (item.value.type == '') {
+                that.pass = false
+                this.selectType(item)
+                return this.$message.error("请填写客服类型");
+              } else if (item.value.type == 1) {
+                if (!item.value.id || item.value.id == '') {
+                  that.pass = false
+                  this.selectType(item)
+                  return this.$message.error("请填写企业ID");
+                } else if (!item.value.target || item.value.target == '') {
+                  that.pass = false
+                  this.selectType(item)
+                  return this.$message.error("请填写跳转地址");
+                }
+              } else if (item.value.type == 2) {
+                if (!item.value.target || item.value.target == '') {
+                  that.pass = false
+                  this.selectType(item)
+                  return this.$message.error("请填写跳转地址");
+                }
+              }
+            }
+            break;
+          case 'product':
+            {
+              if (!item.value.productList || item.value.productList.length == 0) {
+                that.pass = false
+                this.selectType(item)
+                return this.$message.error("请选择商品");
+              }
+            }
+            break;
+          default:
+            break;
+
+        }
+      })
+      return that.pass
+    }
+  }
+}
+</script>
+
+<style scoped>
 #app {
   font-family: Avenir, Helvetica, Arial, sans-serif;
   -webkit-font-smoothing: antialiased;
@@ -17,16 +544,345 @@
   color: #2c3e50;
 }
 
-nav {
-  padding: 30px;
+.header {
+  display: flex;
+  width: 100%;
+  height: 44px;
+  background-color: #fff;
+  align-items: center;
+  justify-content: flex-end;
+}
 
-  a {
-    font-weight: bold;
-    color: #2c3e50;
+.tplName {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100%;
+  flex: 1;
+}
 
-    &.router-link-exact-active {
-      color: #42b983;
-    }
-  }
+.tplName input {
+  width: 199px;
+  font-size: 16px;
+  outline: none;
+  border: 0;
+  border-bottom: 1px solid #ddd;
+  height: 30px;
+  background-color: #fff;
+}
+
+.button-group {
+  margin-right: 15px;
+  position: absolute;
+}
+
+.decoration-edit {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0 0 10px 0;
+  background: #f7f8f9;
+  height: calc(100vh - 70px);
+  position: relative;
+}
+
+.decoration-edit .cover {
+  padding: 10px 20px 10px 10px;
+  height: 110px;
+}
+
+.decoration-edit .cover img {
+  max-width: 100%;
+  max-height: 100%;
+  position: relative;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+}
+
+.decoration-edit .updataBtn {
+  padding: 0px 30px 10px 20px;
+}
+
+.decoration-edit .l,
+.r {
+  width: 380px;
+  height: 100%;
+  padding: 0 0 15px 0;
+  background: #fff;
+  overflow-y: auto;
+}
+
+.decoration-edit .l {
+  width: 220px;
+  margin-right: 160px;
+}
+
+.decoration-edit .l .title {
+  position: relative;
+  font-weight: bold;
+  padding-left: 10px;
+  margin-bottom: 20px;
+}
+
+.decoration-edit .l .title:before {
+  content: "";
+  position: absolute;
+  top: 50%;
+  left: 0;
+  transform: translateY(-50%);
+  width: 3px;
+  height: 18px;
+  background: #1890ff;
+  opacity: 1;
+  border-radius: 2px;
+}
+
+.nobackground {
+  background: unset !important;
+}
+
+.decoration-edit .l::-webkit-scrollbar,
+.r::-webkit-scrollbar {
+  width: 6px;
+}
+
+.decoration-edit .l::-webkit-scrollbar-thumb,
+.r::-webkit-scrollbar-thumb {
+  background: #dbdbdb;
+}
+
+.decoration-edit .l::-webkit-scrollbar-track,
+.r::-webkit-scrollbar-track {
+  background: #f6f6f6;
+}
+
+.decoration-edit .l ul {
+  margin: 0;
+  padding: 0;
+}
+
+.decoration-edit ul li {
+  width: 80px;
+  height: 80px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: column;
+  cursor: default;
+  list-style: none;
+  font-size: 14px;
+  color: #666;
+  float: left;
+  margin: 0 10px;
+  border-radius: 6px;
+  transition: all .3s;
+  cursor: pointer;
+}
+
+.decoration-edit ul li:hover {
+  background: #efefef;
+}
+
+.decoration-edit ul span {
+  display: block;
+  font-size: 40px;
+  margin-bottom: 8px;
+  color: #999;
+}
+
+.decoration-edit ul img {
+  display: block;
+  width: 50px;
+  margin-bottom: 8px;
+}
+
+ul p {
+  display: block;
+  margin: 0;
+  font-size: 12px;
+}
+
+.decoration-edit .c {
+  width: auto;
+  /* max-width: 400px; */
+  max-width: 370px;
+  position: relative;
+  flex: 1;
+}
+
+.decoration-edit .c .top-nav {
+  position: absolute;
+  top: 0;
+  background: #fff;
+  z-index: 999;
+  transition: all .3s;
+}
+
+.decoration-edit .c .top-nav * {
+  pointer-events: none;
+}
+
+/* .decoration-edit .top-nav:hover {
+  transform: scale(0.95);
+  border-radius: 10px;
+  overflow: hidden;
+  box-shadow: 0 0 10px #afafaf;
+} */
+
+.decoration-edit .top-nav .tit {
+  position: absolute;
+  left: 50%;
+  bottom: 10px;
+  transform: translateX(-50%);
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  overflow: hidden;
+  max-width: 50%;
+}
+
+.decoration-edit .top-nav img {
+  max-width: 100%;
+  image-rendering: -moz-crisp-edges;
+  image-rendering: -o-crisp-edges;
+  image-rendering: -webkit-optimize-contrast;
+  image-rendering: crisp-edges;
+  -ms-interpolation-mode: nearest-neighbor;
+}
+
+.decoration-edit .view-content {
+  /* width: 400px; */
+  /* height: 700px; */
+  width: 370px;
+  height: 560px;
+  background: #f5f5f5;
+  overflow-y: auto;
+  overflow-x: hidden;
+  padding-top: 72px;
+  box-shadow: 0 2px 6px #ccc;
+}
+
+.decoration-edit .view-content::-webkit-scrollbar {
+  width: 6px;
+}
+
+.decoration-edit .view-content::-webkit-scrollbar-thumb {
+  background: #dbdbdb;
+}
+
+.decoration-edit .view-content::-webkit-scrollbar-track {
+  background: #f6f6f6;
+}
+
+.decoration-edit .view-content .item {
+  transition: all .3s;
+  background: #fff;
+
+}
+
+.decoration-edit .view-content .item:hover {
+  transform: scale(0.95);
+  border-radius: 10px;
+  box-shadow: 0 0 10px #afafaf;
+}
+
+.decoration-edit .view-content .item:hover .el-icon-error {
+  display: block;
+}
+
+.decoration-edit .view-content .item:hover .control-tool-bar {
+  display: block;
+}
+
+.decoration-edit .view-content .item div {
+  pointer-events: none;
+}
+
+.decoration-edit .view-content .item .wait {
+  background: #deedff;
+  height: 35px;
+  text-align: center;
+  line-height: 35px;
+  font-size: 12px;
+  color: #666;
+}
+
+.decoration-edit .view-content .item .el-icon-error {
+  position: absolute;
+  right: -10px;
+  top: -6px;
+  color: red;
+  font-size: 25px;
+  cursor: pointer;
+  display: none;
+  z-index: 9999;
+}
+
+.decoration-edit .view-content .item .control-tool-bar {
+  position: absolute;
+  top: 0;
+  left: 50%;
+  width: 66px;
+  transform: translateX(-50%);
+  z-index: 9998;
+  pointer-events: unset;
+  display: none;
+}
+
+.decoration-edit .view-content .item .control-tool-bar .ctrl-icon {
+  width: 33px;
+  height: 33px;
+  margin-left: 0;
+  margin-bottom: 2px;
+  background-color: #fff;
+  -webkit-box-shadow: 0 0 4px 2px rgb(0 0 0 / 10%);
+  box-shadow: 0 0 4px 2px rgb(0 0 0 / 10%);
+  border-radius: 4px;
+  background-repeat: no-repeat;
+  background-position: 50%;
+}
+
+.decoration-edit .view-content .item .control-tool-bar .icon-up {
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3BpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQyIDc5LjE2MDkyNCwgMjAxNy8wNy8xMy0wMTowNjozOSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1ZjA2NzFlZS0yODUwLWMyNDMtYWQzNS00YzEzY2I2ZDFhZmIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6Q0VGMTU4N0Y3RTJEMTFFQTgwMUNFQjgwRkEwOUFENzkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6Q0VGMTU4N0U3RTJEMTFFQTgwMUNFQjgwRkEwOUFENzkiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBNUJFQTg0MTdENkUxMUVBODc0MkE4MTAxQTY0ODkxQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBNUJFQTg0MjdENkUxMUVBODc0MkE4MTAxQTY0ODkxQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Psjmc8UAAADNSURBVHjaYvz//z8DLQATA43AwBtcV1c3B4hNiVXPSEwYAw2cBKRygfg1EMs3NTV9p9jFQEMroIaCgCgQH6U4KICGFgCpdjRhQ6D4cbKDAqg5CEitxaN3PTBIgkhyMdBQCwKGgkAgUN0Eog0GKo4CUseJjPx8oPo12CRYsIgJAfFeIP4AxFxA7IlFzRUgvg7EnGQnN6CLsClIBYbvHEpShSQOKQFK0zEzuel/GBdC1DaYBYc4DwOZGmHgMxC/A2JWNPGHVCk2R0bkAQQYAEdHPS1kdX1UAAAAAElFTkSuQmCC);
+}
+
+.decoration-edit .view-content .item .control-tool-bar .icon-up.is-disabled,
+.decoration-edit .view-content .item .control-tool-bar .icon-up.is-disabled:hover {
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA4ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQyIDc5LjE2MDkyNCwgMjAxNy8wNy8xMy0wMTowNjozOSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1ZjA2NzFlZS0yODUwLWMyNDMtYWQzNS00YzEzY2I2ZDFhZmIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QTVCRUE4NDI3RDZFMTFFQTg3NDJBODEwMUE2NDg5MUIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QTVCRUE4NDE3RDZFMTFFQTg3NDJBODEwMUE2NDg5MUIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4YWNlODEyNi1kZWFkLTQzNDYtOGRhOC00MmFlMDYxMmI0ZGYiIHN0UmVmOmRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDpiMzgxMjliYS02OTNiLTJmNDgtOThhZS1mYzkxMGE4ZGYzZTAiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5lL4zAAAAAzUlEQVR42mL8//8/Ay0AEwONwMAb/Pz58zlAbEqsekZiwhho4CQglQvEr4FYXlJS8jvFLgYaWgE1FAREgfgoxUEBNLQASLWjCRsCxY+THRRAzUFAai0eveuBQRJEkouBhloQMBQEAoHqJhBtMFBxFJA6TmTk5wPVr8EmwYJFTAiI9wLxByDmAmJPLGquAPF1IOYkO7kBXYRNQSowfOdQkiokcUgJUJqOmclN/8O4EKK2wSw4xHkYyNQIA5+B+B0Qs6KJP6RKsTkyIg8gwABPpUl7JDE4ewAAAABJRU5ErkJggg==);
+}
+
+.decoration-edit .view-content .item .control-tool-bar .icon-down {
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3BpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQyIDc5LjE2MDkyNCwgMjAxNy8wNy8xMy0wMTowNjozOSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1ZjA2NzFlZS0yODUwLWMyNDMtYWQzNS00YzEzY2I2ZDFhZmIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QTNBRUJGODk3RTJGMTFFQUI4NkRDMzY1NkIyMzY1M0EiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QTNBRUJGODg3RTJGMTFFQUI4NkRDMzY1NkIyMzY1M0EiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpCOEQyMTUwMTdENkUxMUVBODc0MkE4MTAxQTY0ODkxQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpCOEQyMTUwMjdENkUxMUVBODc0MkE4MTAxQTY0ODkxQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqOiNT4AAADgSURBVHjaYvz//z8DLQATA40ACyEFdXV10kCqHYiFoULfgbirqanpFEUGA0ELEMeiiRkDsSKlQcFOqzD+QaQYfSJveBr8F4vYf2oY/J8cgxmxZWlgprgDTeO/gFgciPnQlIDEH0EdxgXMLJLEungrEMsDsSoWQ0GADYhVgFgJiK8QHRRAF+QDqQ4igukQUK0r0UGBFCTLgFQkDunzQEONyIo8oMYoILUPi9Q7ILYiOfKwuPw8kDJAKt20gJY+oEYGsUVimxIylGgXQ11tCqTkgIauJUY945CrmmhmMECAAQCTB0MOORfSxwAAAABJRU5ErkJggg==);
+}
+
+.decoration-edit .view-content .item .control-tool-bar .icon-down.is-disabled,
+.decoration-edit .view-content .item .control-tool-bar .icon-down.is-disabled:hover {
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3BpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQyIDc5LjE2MDkyNCwgMjAxNy8wNy8xMy0wMTowNjozOSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1ZjA2NzFlZS0yODUwLWMyNDMtYWQzNS00YzEzY2I2ZDFhZmIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RTExNDM5QjQ3RTJFMTFFQTlFQjdEMTA2RjhFQzc3QTAiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RTExNDM5QjM3RTJFMTFFQTlFQjdEMTA2RjhFQzc3QTAiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpCOEQyMTUwMTdENkUxMUVBODc0MkE4MTAxQTY0ODkxQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpCOEQyMTUwMjdENkUxMUVBODc0MkE4MTAxQTY0ODkxQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Poa9sGQAAADjSURBVHjaYvz//z8DLQATA40ACyEFz58/lwZS7UAsDBX6DsRdkpKSpygyGAhagDgWTcwYiBUpDQp2WoXxDyLF6BN5w9Pgv1jE/lPD4P/kGMyILUsDM8UdaBr/BcTiQMyHpgQk/gjqMC5gZpEk1sVbgVgeiFWxGAoCbECsAsRKQHyF6KAAOiAfSHUQEUyHgGpdiQ4KpCBZBqQicUifBxpqRFbkATVGAal9WKTeAbEVRakCaLgzkLqAJAQq3YyB4j+okUFskdimQEMfkJXccIS3KZCSAxq6lhj1jEOuaqKZwQABBgC4Mzjx6VYCZQAAAABJRU5ErkJggg==);
+}
+
+.decoration-edit .view-content .item .control-tool-bar .ctrl-icon.is-disabled {
+  background-color: #fff;
+}
+
+.decoration-edit .submit-btn {
+  position: absolute;
+  bottom: 30px;
+  left: 50%;
+  transform: translateX(-50%);
+}
+
+/* 悬浮组件 */
+.left-top {
+  position: absolute;
+  top: 100px;
+  left: 20px;
+  z-index: 200;
+}
+
+.right-bottom {
+  position: absolute;
+  bottom: 50px;
+  right: 20px;
+  z-index: 200;
 }
 </style>

BIN
src/assets/images/check_gou.png


BIN
src/assets/images/defaultimg.jpg


BIN
src/assets/images/kefu.png


BIN
src/assets/images/kefu2.png


BIN
src/assets/images/l-baomingbiao.png


BIN
src/assets/images/l-kefu.png


BIN
src/assets/images/l-lunbo.png


BIN
src/assets/images/l-shangping.png


BIN
src/assets/images/l-tupian.png


BIN
src/assets/images/l-wenbeng.png


BIN
src/assets/images/resouceNone.png


BIN
src/assets/images/topNavBlack.png


+ 0 - 59
src/components/HelloWorld.vue

@@ -1,59 +0,0 @@
-<template>
-  <div class="hello">
-    <h1>{{ msg }}</h1>
-    <p>
-      For a guide and recipes on how to configure / customize this project,<br>
-      check out the
-      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
-    </p>
-    <h3>Installed CLI Plugins</h3>
-    <ul>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
-    </ul>
-    <h3>Essential Links</h3>
-    <ul>
-      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
-      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
-      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
-      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
-      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
-    </ul>
-    <h3>Ecosystem</h3>
-    <ul>
-      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
-      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
-      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
-      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
-      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
-    </ul>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'HelloWorld',
-  props: {
-    msg: String
-  }
-}
-</script>
-
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped lang="scss">
-h3 {
-  margin: 40px 0 0;
-}
-ul {
-  list-style-type: none;
-  padding: 0;
-}
-li {
-  display: inline-block;
-  margin: 0 10px;
-}
-a {
-  color: #42b983;
-}
-</style>

+ 121 - 0
src/components/View/editorApplicationForm.vue

@@ -0,0 +1,121 @@
+<template>
+    <div class="formDiv">
+        <div v-if="content.value.title.isShow" class="form-title">{{ content.value.title.value }}</div>
+        <div class="form-bar">
+            <div class="form-item" v-for="item in content.value.formItemList">
+                <div class="form-label"><span :style="item.required ? '' : 'visibility: hidden;'"
+                        style="color:red;margin-right: 5px;">*</span>{{ item.label?item.label:'编辑文本' }}</div>
+                <div class="form-input" v-if="item.type == 1">
+                    <input :placeholder="'请填写' + item.label" />
+                </div>
+                <div class="form-input" v-if="item.type == 2">
+                    <input :placeholder="'请填写' + item.label" />
+                </div>
+                <div class="form-input" v-if="item.type == 3">
+                    <input :placeholder="'请填写' + item.label" />
+                </div>
+                <div class="form-input" v-if="item.type == 4">
+                    <textarea :placeholder="'请填写' + item.label"></textarea>
+                </div>
+                <div class="form-input" v-if="item.type == 5">
+                    <input :placeholder="'请选择' + item.label" />
+                    <i class="el-icon-arrow-right"></i>
+                </div>
+                <div class="form-input" v-if="item.type == 6">
+                    <input :placeholder="'请填写' + item.label" />
+                </div>
+                <div class="form-input" v-if="item.type == 7">
+                    <input :placeholder="'请填写' + item.label" />
+                </div>
+                <div class="form-input" v-if="item.type == 8">
+                    <input :placeholder="'请填写' + item.label" />
+                </div>
+                <div class="form-input" v-if="item.type == 9">
+                    <input :placeholder="'请填写' + item.label" />
+                </div>
+            
+            
+            </div>
+        </div>
+        <div style="margin: 10px 20px;box-sizing: border-box;">
+            <el-button style="width: 100%;" type="primary" @click="">
+                {{ content.value.buttonName ? content.value.buttonName : '提交' }}</el-button>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'editorApplicationForm',
+    props: ['data', 'className'],
+    data() {
+        return {
+            content: JSON.parse(JSON.stringify(this.data)),
+            form: {}
+        }
+    },
+    watch: {
+        data: {
+            deep: true,
+            handler(val) {
+                this.content = JSON.parse(JSON.stringify(val));
+            },
+        },
+    },
+}
+</script>
+
+<style  scoped>
+.formDiv {
+    padding: 10px;
+}
+
+.form-title {
+    margin: 10px 20px;
+    color: #333333;
+    font-size: 16px;
+    font-weight: 400;
+}
+
+.form-item {
+    display: flex;
+    justify-content: space-between;
+    padding: 10px 0px;
+    margin: 10px 20px;
+    border-bottom: 1px solid #eeeeee;
+    align-items: center;
+}
+
+.form-bar .form-item .form-label {
+    width: 75px;
+    font-size: 14px;
+    color: #333;
+}
+
+.form-bar .form-item .form-input {
+    flex: 1;
+    display: flex;
+    align-items: center;
+}
+
+.form-bar .form-item .form-input input {
+    border: none;
+    width: 100%;
+    padding: 10px;
+    border-radius: 5px;
+}
+
+.form-bar .form-item .form-input textarea {
+    width: 100%;
+    border: 1px solid #eeeeee;
+    padding: 10px;
+    border-radius: 5px;
+    resize: vertical;
+}
+
+.form-bar .form-item .form-input input:focus,
+.form-bar .form-item .form-input textarea:focus {
+    border: 1px solid #409EFF;
+    outline: none;
+}
+</style>

+ 48 - 0
src/components/View/editorBanner.vue

@@ -0,0 +1,48 @@
+<template>
+    <div class="banner">
+        <el-carousel height="170px" trigger="click" arrow="never" v-if="data.value.imageList.length > 0">
+            <el-carousel-item v-for="item, index in data.value.imageList" :key="index">
+                <img v-if="item.src" :src="item.src">
+                <img v-else src="../../assets/images/defaultimg.jpg" />
+            </el-carousel-item>
+        </el-carousel>
+        <div class="image-null" v-else><span class="el-icon-picture"></span></div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'editorBanner',
+    props: ['data']
+}
+</script>
+
+<style  scoped>
+.banner {
+    font-size: 0;
+    padding: 10px;
+}
+
+img {
+    width: 100%;
+    border-radius: 5px;
+}
+
+.el-carousel__indicator--horizontal {
+    padding: 12px 4px;
+}
+
+.el-carousel__button {
+    width: 12px;
+}
+
+.image-null {
+    background: #ffffff;
+    height: 176px;
+    font-size: 50px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    color: #c1c1c1;
+}
+</style>

+ 37 - 0
src/components/View/editorCustomerService.vue

@@ -0,0 +1,37 @@
+<template>
+    <div>
+        <img :style="'width:'+(data.width?data.width:100)+'px;height:'+(data.height?data.height:100)+'px;'" src="../../assets/images/kefu2.png"/>
+        <!-- <div class="text">{{ data.value.text ? data.value.text : '客服' }}</div> -->
+    </div>
+
+</template>
+
+<script>
+export default {
+    name: 'editorCustomerService',
+    props: ['data', 'className'],
+    data() {
+        return {
+            content: this.data,
+        }
+    },
+    // watch: {
+    //     data: {
+    //         deep: true,
+    //         handler(val) {
+    //             this.content = val;
+    //         },
+    //     },
+    // },
+}
+</script>
+
+<style  scoped>
+.text{
+    margin: auto;
+    text-align: center;
+}
+img{
+    border-radius: 50%;
+}
+</style>

+ 25 - 0
src/components/View/editorImage.vue

@@ -0,0 +1,25 @@
+<template>
+    <div class="img-bar">
+        <img v-if="data.value.src" :src="data.value.src">
+        <img v-else src="../../assets/images/defaultimg.jpg"/>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'editorImage',
+    props: ['data', 'className']
+}
+</script>
+
+<style  scoped>
+.img-bar{
+    padding: 10px 20px;
+}
+img{
+    width: 100%;
+    /* height:150px; */
+    border-radius: 5px;
+}
+
+</style>

+ 200 - 0
src/components/View/editorProduct.vue

@@ -0,0 +1,200 @@
+<template>
+    <div class="product" :class="className">
+        <template v-if="content.value.productList && content.value.productList.length > 0">
+            <div class="product-item" v-for="(item, index) in content.value.productList" :key="index">
+                <div class="image">
+                    <img :src="item.pic">
+                </div>
+                <div class="info">
+                    <p class="name">{{ item.title }}</p>
+                    <!-- <p class="num">
+                        {{ options.volumeStr ? item.volumeStr + ' 已购买' : '' }} {{ line }} {{ options.goodRatio ?
+                                item.goodRatio + '99%' : ''
+                        }}
+                    </p> -->
+                    <p class="price">
+                        <span>¥<span>{{ item.minSalePrice?item.minSalePrice:0 }}</span>
+                        </span>
+                        <span v-if="content.value.showOriginalPrice">¥{{ item.originalPrice }}</span>
+                    </p>
+                </div>
+            </div>
+        </template>
+        <template v-else>
+            <div class="product-item product-default" v-for="index in 3" :key="index">
+                <div class="image">
+                    <img src="../../assets/images/defaultimg.jpg" alt="">
+                </div>
+                <div class="info">
+                    <p class="name">商品名称</p>
+                    <!-- <p class="num">
+                        12124 已购买 | 99%
+                    </p> -->
+                    <p class="price">
+                        <span>¥价格</span>
+                        <span v-if="content.value.showOriginalPrice">¥划线价</span>
+                    </p>
+                </div>
+            </div>
+        </template>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'editorProduct',
+    props: ['data'],
+    data() {
+        return {
+            content: this.data,
+        }
+    },
+    watch: {
+        data: {
+            deep: true,
+            handler(val) {
+                this.content = val;
+            },
+        },
+    },
+    computed: {
+        className() {
+            switch (this.data.value.layoutNum) {
+                case 1:
+                    return 'one'
+                    break;
+                case 2:
+                    return ''
+                    break;
+                case 3:
+                    return 'three'
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+}
+</script>
+
+<style  scoped>
+.product {
+    display: flex;
+    flex-wrap: wrap;
+    padding: 4px 8px;
+    box-sizing: border-box;
+}
+
+.product * {
+    box-sizing: border-box;
+}
+
+
+/* 一行单个商品 */
+.product.one .product-item {
+    width: 100%;
+    padding: 10px;
+    display: flex;
+    border-bottom: 1px dashed #eee;
+}
+
+.product.one .product-item .image {
+    width: 100px;
+    border-radius: 5px;
+    overflow: hidden;
+    margin-right: 10px;
+}
+
+.product.one .product-item .info {
+    padding: 0 5px;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    flex: 1;
+}
+
+.product.one .product-item .info .price {
+    font-size: 20px;
+    margin: 0;
+}
+
+.product.one .product-item .info .num {
+    margin: 12px 0 0;
+}
+
+
+/* 一行三个商品 */
+.product.three .product-item {
+    width: 33.33%;
+}
+
+.product.three .product-item .info .price {
+    font-size: 16px;
+}
+
+.product.three .product-item.product-default:nth-of-type(3) {
+    display: block;
+}
+
+
+.product .product-item {
+    width: 50%;
+    padding: 5px;
+}
+
+.product .product-item.product-default:nth-of-type(3) {
+    display: none;
+}
+
+.product .product-item .image {
+    font-size: 0;
+}
+
+.product .product-item .image img {
+    max-width: 100%;
+    max-height: 100px;
+}
+
+
+.product .product-item .info {
+    padding: 10px 5px 0;
+}
+
+.product .product-item .info .name {
+    font-size: 14px;
+    margin: 0;
+    color: #333;
+    text-overflow: ellipsis;
+    word-break: break-all;
+    display: -webkit-box;
+    -webkit-line-clamp: 2;
+    -webkit-box-orient: vertical;
+    overflow: hidden;
+    height: 38px;
+    line-height: 18px;
+}
+
+.product .product-item .info .num {
+    font-size: 12px;
+    color: #d23000;
+    font-weight: 600;
+}
+
+.product .product-item .info .price {
+    font-weight: 600;
+    margin: 12px 0 0;
+    font-size: 18px;
+}
+
+.product .product-item .info .price span:nth-of-type(1) {
+    color: red;
+}
+
+.product .product-item .info .price span:nth-of-type(2) {
+    color: #b5b5b5;
+    font-weight: 400;
+    font-size: 12px;
+    margin-left: 4px;
+    text-decoration: line-through;
+}
+</style>

+ 40 - 0
src/components/View/editorText.vue

@@ -0,0 +1,40 @@
+<template>
+    <div>
+        <div :class="data.value.isTitle ? 'text-bar istitle' : 'text-bar'">{{ data.value.content ? data.value.content : '编辑文本' }}</div>
+    </div>
+
+</template>
+
+<script>
+export default {
+    name: 'editorText',
+    props: ['data', 'className'],
+    data() {
+        return {
+            content: this.data,
+        }
+    },
+    // watch: {
+    //     data: {
+    //         deep: true,
+    //         handler(val) {
+    //             this.content = val;
+    //         },
+    //     },
+    // },
+}
+</script>
+
+<style  scoped>
+.text-bar {
+    padding: 10px 20px;
+    line-height: 26px;
+    white-space: pre-wrap;
+    word-break: break-word;
+}
+
+.istitle {
+    font-weight: bold;
+    font-size: 16px;
+}
+</style>

+ 471 - 0
src/components/materialManage.vue

@@ -0,0 +1,471 @@
+<template>
+    <el-dialog :title="fileType === 1 ? `图片素材` : `视频素材`" :visible.sync="visible" width="1100px"
+        :before-close="dialogBeforeClose" :close-on-click-modal="false" :close-on-press-escape="false"
+        class="material-wrapper">
+        <div class="material-cont clearfix">
+            <div class="material-side image-side">
+                <div class="pictrue-tabs">{{ fileType === 1 ? "我的图片" : "我的视频" }}</div>
+                <div class="side-btns">
+                    <div class="file-upload">
+                        <!-- <el-upload class="upload-demo" action="/api/sys/oss/upload" :on-success="imageUploadSuccess"
+                            :show-file-list="false">
+                            <el-button size="small" type="primary">{{ fileType === 1 ? "上传图片" : "上传视频" }}</el-button>
+                        </el-upload> -->
+                        <el-upload class="upload-demo" action="/sys/oss/upload" :on-success="imageUploadSuccess"
+                            :show-file-list="false">
+                            <el-button size="small" type="primary">{{ fileType === 1 ? "上传图片" : "上传视频" }}</el-button>
+                        </el-upload>
+                    </div>
+                </div>
+            </div>
+            <div class="material-list image-list" element-loading-text="加载中" v-loading="dataListLoading">
+                <div>
+                    <!-- <el-input clearable v-model="dataForm.title" placeholder="请输入素材名称" size="mini"
+                        style="margin-bottom: 14px; width: 200px; margin-right: 10px;"></el-input>
+                    <el-button type="primary" @click="getDataList" size="mini">搜索</el-button> -->
+                    <div v-if="dataList.length > 0">
+                        <ul class="list-box image-box clearfix" v-if="fileType === 1">
+                            <li class="image-item list-item" @click="chooseMediaByIndexHandle(index)"
+                                :class="{ active: isAllOption }" v-for="(item, index) in dataList" :key="index">
+                                <div class="del-btn" v-if="item.checked">✕</div>
+                                <span class="checked-item" v-if="item.checked"></span>
+                                <img class="bg-img" :src="item.url" alt="" />
+                                <div class="inline-text-editor"><input maxlength="50" readonly="readonly"
+                                        v-model="item.title"></div>
+                            </li>
+                        </ul>
+                        <ul class="list-box video-box clearfix" v-if="fileType === 2">
+                            <li class="video-item list-item" @click="chooseMediaByIndexHandle(index)"
+                                :class="{ active: isAllOption }" v-for="(item, index) in dataList" :key="index">
+                                <div class="del-btn" v-if="item.checked">✕</div>
+                                <span class="checked-item" v-if="item.checked"></span>
+                                <video :src="item.src" poster=""></video>
+                                <div class="inline-text-editor"><input maxlength="50" readonly="readonly"
+                                        :value="item.title"></div>
+                                <div class="video-info clearfix">
+                                    <div class="video-info-left" v-if="false">1280*720</div>
+                                    <div class="video-info-right" v-if="false">5.65MB</div>
+                                </div>
+                                <div class="video-duration" v-if="false">00:50</div>
+                            </li>
+                        </ul>
+                    </div>
+                    <div class="resourceNone" v-else>
+                        <img src="@/assets/images/resouceNone.png"
+                            style="display: block;;width:400px;margin:20px auto 0" alt="" />
+                        <p style="text-align: center;">Sorry,没有搜到相关内容</p>
+                    </div>
+                    <div class="list-footer clearfix" v-if="page > 1 || dataList.length > 0">
+                        <div class="list-ctrl">
+                            <el-button size="small" @click="batchOptions" v-if="!isAllOption">批量操作</el-button>
+                            <el-button type="primary" @click="completeMediaHandle" size="small" v-if="isAllOption">完成
+                            </el-button>
+                            <el-button size="small" @click="deleteMediaHandle" class="ctrl-del" v-if="isAllOption">删除
+                            </el-button>
+                            <el-checkbox v-model="checked" @change="chooseMediaHandle" v-if="isAllOption">全选
+                            </el-checkbox>
+                        </div>
+                        <div class="list-page">
+                            <el-pagination :current-page="page" :page-sizes="[15, 30, 75, 150]" :page-size="limit"
+                                :total="total" layout="total, sizes, prev, pager, next, jumper"
+                                @size-change="pageSizeChangeHandle" @current-change="pageCurrentChangeHandle">
+                            </el-pagination>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </el-dialog>
+</template>
+
+<script>
+import service from "@/utlis/axios";
+var that = null
+export default {
+    name: 'materialManage',
+    props: {
+        fileType: {
+            type: Number,
+            required: true
+        },
+        itemOrSrc: {
+            type: String,
+        },
+        onSuccess: {
+            type: Function,
+            required: true
+        }
+    },
+    data: function () {
+        return {
+            visible: false,
+            mixinViewModuleOptions: {
+                getDataListURL: '/material/page',
+            },
+            dataForm: {
+                fileType: 1,
+                title: ''
+            },
+            dataList: [],
+            page: 1,                    // 当前页码
+            limit: 15,                  // 每页数
+            total: 0,                   // 总条数
+            dataListLoading: false,     // 数据列表,loading状态
+            dataListSelections: [],     // 数据列表,多选项
+
+            isAllOption: false,
+            checked: false
+        }
+    },
+    beforeCreate: function () {
+        that = this;
+    },
+    created: function () {
+        that.dataForm.fileType = that.fileType;
+        that.visible = true;
+        that.query()
+    },
+    methods: {
+        imageUploadSuccess: function (json) {
+            that.getDataList();
+        },
+        query: function () {
+            that.dataListLoading = true;
+            service.get("/sys/oss/page", {
+                params: {
+                    page: that.page,
+                    limit: that.limit,
+                    fileType: that.dataForm.fileType,
+                }
+            }).then((res) => {
+                that.dataListLoading = false;
+                if (res.data.code != 0) {
+                    that.dataList = [];
+                    that.total = 0;
+                    return that.$message.error(res.data.data.msg);
+                }
+                that.dataList = res.data.data.list;
+                that.total = res.data.data.total;
+            }).catch(function () {
+                that.dataListLoading = false;
+            });
+        },
+        // 分页, 每页条数
+        pageSizeChangeHandle: function (val) {
+            that.page = 1;
+            that.limit = val;
+            that.query();
+        },
+        // 分页, 当前页
+        pageCurrentChangeHandle: function (val) {
+            that.page = val;
+            that.query();
+        },
+        getDataList: function () {
+            that.page = 1;
+            that.query();
+        },
+        dialogBeforeClose: function () {
+            that.visible = false;
+            that.$parent.materialVisible = false;
+        },
+        batchOptions: function () {
+            that.dataList = that.dataList.map(s => {
+                s.checked = true;
+                return s;
+            })
+            that.checked = true;
+            that.isAllOption = true;
+        },
+        chooseMediaByIndexHandle: function (index) {
+            if (that.isAllOption) { //操作
+                that.$set(that.dataList[index], 'checked', !that.dataList[index].checked);
+                that.$forceUpdate();
+            } else { //选择图片
+                that.visible = false;
+                if (that.itemOrSrc && that.itemOrSrc == 'item') {
+                    that.onSuccess.call(this, that.dataList[index]);
+                } else {
+                    that.onSuccess.call(this, that.dataList[index].src);
+                }
+            }
+        },
+        chooseMediaHandle: function () {
+            //全部操作
+            that.dataList = that.dataList.map(s => {
+                s.checked = that.checked;
+                return s;
+            })
+        },
+        completeMediaHandle: function () {
+            that.dataList = that.dataList.map(s => {
+                s.checked = false;
+                return s;
+            })
+            that.checked = false;
+            that.isAllOption = false;
+        },
+        deleteMediaHandle: function () {
+            if (!that.dataList.some(ss => ss.checked)) {
+                return that.$message.error('未选择文件');
+            }
+            that.$confirm('删除?', '删除', {
+                confirmButtonText: '确认',
+                cancelButtonText: '取消',
+                type: 'warning'
+            }).then(function () {
+                service.delete('/sys/oss', { 'data': that.dataList.filter(item=> {return item.checked==true}).map(item => item.id) })
+                    .then(function (res) {
+                        if (res.data.code !== 0) return that.$message.error(res.data.msg);
+                        that.$message({
+                            message: '操作成功',
+                            type: 'success',
+                            duration: 500,
+                            onClose: function () {
+                                that.query();
+                            }
+                        });
+                    }).catch(function () {
+                    });
+            }).catch(function () {
+            });
+        }
+    }
+}
+</script>
+
+<style scoped>
+.clearfix:after {
+    visibility: hidden;
+    display: block;
+    font-size: 0;
+    content: " ";
+    height: 0;
+}
+
+.clearfix:after {
+    content: "";
+    display: table;
+    clear: both;
+}
+
+/* 弹窗 */
+.el-dialog__wrapper .el-dialog .el-dialog__header {
+    padding-top: 16px;
+    padding-bottom: 16px;
+    border-bottom: 1px solid #dcdcdc;
+}
+
+/* 图片素材 */
+.material-wrapper .el-dialog__body {
+    padding: 0 !important;
+}
+
+.material-side {
+    float: left;
+    position: relative;
+    width: 180px;
+    text-align: center;
+    border-right: 1px solid #eaeff4;
+    box-sizing: border-box;
+    padding-right: 20px;
+}
+
+.material-side.image-side {
+    height: 640px;
+}
+
+.pictrue-tabs {
+    width: 160px;
+    height: 50px;
+    line-height: 50px;
+    padding-left: 24px;
+    text-align: left;
+    background: #edf1ff;
+    box-sizing: border-box;
+}
+
+.material-side .side-btns {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    width: 100%;
+    padding-bottom: 14px;
+}
+
+.file-upload {
+    display: inline-block;
+}
+
+.material-side .side-btns .el-button {
+    display: block;
+    width: 132px;
+    margin: 10px auto;
+    border-radius: 16px;
+}
+
+.material-list {
+    float: left;
+    width: 820px;
+    box-sizing: border-box;
+    overflow: hidden;
+}
+
+.material-list.image-list {
+    padding: 24px 18px;
+}
+
+.material-list .list-box.image-box {
+    height: 510px;
+}
+
+.material-list .list-box.video-box {
+    height: 450px;
+}
+
+.material-list .list-box .list-item {
+    position: relative;
+    box-sizing: border-box;
+    cursor: pointer;
+}
+
+.material-list .list-box .image-item {
+    float: left;
+    display: block;
+    width: 130px;
+    height: 130px;
+    margin: 0 6px 40px;
+    background: #e0e0e0;
+}
+
+.material-list .list-box .image-item .bg-img {
+    width: 100%;
+    height: 100%;
+    box-sizing: border-box;
+    background-size: contain;
+    background-repeat: no-repeat;
+    background-position: 50%;
+}
+
+.material-list .list-box .video-item {
+    float: left;
+    display: block;
+    width: 130px;
+    height: 130px;
+    margin: 0 6px 40px;
+    background: #e0e0e0;
+}
+
+.material-list .list-box .video-item video {
+    display: block;
+    width: 100%;
+    height: 100%;
+    box-sizing: border-box;
+}
+
+.inline-text-editor input {
+    display: block;
+    width: 100%;
+    height: 20px;
+    margin: 5px 0;
+    line-height: 20px;
+    border: 1px solid transparent;
+    outline: none;
+    font-size: 14px;
+    color: #53586b;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+}
+
+.material-list .list-box .list-item .del-btn {
+    z-index: 10;
+    position: absolute;
+    top: 5px;
+    right: 5px;
+    display: none;
+    width: 14px;
+    height: 14px;
+    color: #fff;
+    font-size: 12px;
+    text-align: center;
+    line-height: 13px;
+    background: rgba(0, 0, 0, .4);
+    border-radius: 18px;
+    cursor: pointer;
+}
+
+.material-list .list-box .list-item:hover .del-btn {
+    display: block;
+}
+
+.material-list .list-box .list-item.active .checked-item {
+    position: absolute;
+    top: 0;
+    left: 0;
+    display: block;
+    height: 40px;
+    width: 40px;
+    background: url(../assets/images/check_gou.png) no-repeat;
+}
+
+.material-list .list-box .list-item.active .bg-img,
+.material-list .list-box .list-item.active video {
+    border: 2px solid #409eff;
+}
+
+.material-list .list-box .video-item .video-info {
+    width: 100%;
+    font-size: 12px;
+    color: #999;
+}
+
+.material-list .list-box .video-item .video-info-left {
+    float: left;
+    width: 50%;
+    text-align: left;
+}
+
+.material-list .list-box .video-item .video-info-right {
+    float: left;
+    width: 50%;
+    text-align: right;
+}
+
+.material-list .list-box .video-item .video-duration {
+    position: absolute;
+    bottom: 8px;
+    right: 8px;
+    padding: 5px 9px;
+    font-size: 12px;
+    text-align: center;
+    color: #fff;
+    background: #000;
+    border-radius: 2px;
+    opacity: .7;
+}
+
+.material-list .list-footer {
+    margin-top: 8px;
+}
+
+.material-list .list-footer .list-ctrl {
+    float: left;
+    width: 230px;
+    height: 32px;
+}
+
+.material-list .list-footer .list-ctrl .el-button {
+    padding: 9px 24px;
+}
+
+.material-list .list-footer .list-ctrl .ctrl-del {
+    margin: 0 6px;
+}
+
+.material-list .list-footer .list-page {
+    float: right;
+    width: 542px;
+    text-align: right;
+}
+</style>

+ 445 - 0
src/components/productManage.vue

@@ -0,0 +1,445 @@
+<template>
+    <el-dialog title="选择商品" :visible.sync="visible" width="1100px" :before-close="dialogBeforeClose"
+        :close-on-click-modal="false" :close-on-press-escape="false" class="material-wrapper">
+        <div class="material-cont clearfix">
+            <!-- <div class="material-side image-side">
+                <div class="pictrue-tabs">我的商品</div>
+            </div> -->
+            <div class="material-list image-list" element-loading-text="加载中" v-loading="dataListLoading">
+                <div>
+                    <el-input clearable v-model="dataForm.title" placeholder="请输入商品名称" size="mini"
+                        style="margin-bottom: 14px; width: 200px; margin-right: 10px;"></el-input>
+                    <el-button type="primary" @click="getDataList" size="mini">搜索</el-button>
+                    <div v-if="dataList.length > 0">
+                        <ul class="list-box image-box clearfix">
+                            <li class="image-item list-item" @click="chooseMediaByIndexHandle(index)"
+                                :class="{ active: isAllOption || !isAllOption }" v-for="(item, index) in dataList"
+                                :key="index">
+                                <div class="del-btn" v-if="item.checked">✕</div>
+                                <span class="checked-item" v-if="item.checked"></span>
+                                <img class="bg-img" :src="item.pic" alt="" />
+                                <div class="inline-text-editor"><input maxlength="50" readonly="readonly"
+                                        v-model="item.title"></div>
+                            </li>
+                        </ul>
+                    </div>
+                    <div class="resourceNone" v-else>
+                        <img src="@/assets/images/resouceNone.png"
+                            style="display: block;;width:400px;margin:20px auto 0" alt="" />
+                        <p style="text-align: center;">Sorry,没有搜到相关内容</p>
+                    </div>
+                    <div class="list-footer clearfix" v-if="page > 1 || dataList.length > 0">
+                        <div class="list-ctrl">
+                            <el-button size="small" @click="batchOptions" v-if="!isAllOption">批量操作</el-button>
+                            <el-button type="primary" @click="completeMediaHandle" size="small" v-if="isAllOption">完成
+                            </el-button>
+                            <!-- <el-button size="small" @click="deleteMediaHandle" class="ctrl-del" v-if="isAllOption">删除
+                            </el-button> -->
+                            <el-checkbox v-model="checked" @change="chooseMediaHandle" v-if="isAllOption">全选
+                            </el-checkbox>
+                        </div>
+                        <div class="list-page">
+                            <el-pagination :current-page="page" :page-sizes="[18, 30, 78, 150]" :page-size="limit"
+                                :total="total" layout="total, sizes, prev, pager, next, jumper"
+                                @size-change="pageSizeChangeHandle" @current-change="pageCurrentChangeHandle">
+                            </el-pagination>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div style="text-align: right;">
+            <el-button @click="dialogBeforeClose" size="mini">取消</el-button>
+            <el-button type="primary" @click="productHandel" size="mini">确定</el-button>
+        </div>
+    </el-dialog>
+</template>
+
+<script>
+import service from "@/utlis/axios";
+var that = null
+export default {
+    name: 'productManage',
+    props: {
+        onSuccess: {
+            type: Function,
+            required: true
+        }
+    },
+    data: function () {
+        return {
+            visible: false,
+            dataForm: {
+                fileType: 1,
+                title: ''
+            },
+            dataList: [],
+            page: 1,                    // 当前页码
+            limit: 18,                  // 每页数
+            total: 0,                   // 总条数
+            dataListLoading: false,     // 数据列表,loading状态
+            dataListSelections: [],     // 数据列表,多选项
+
+            isAllOption: false,
+            checked: false
+        }
+    },
+    beforeCreate: function () {
+        that = this;
+    },
+    created: function () {
+        that.dataForm.fileType = that.fileType;
+        that.visible = true;
+        that.query()
+    },
+    methods: {
+        imageUploadSuccess: function (json) {
+            that.getDataList();
+        },
+        query: function () {
+            that.dataListLoading = true;
+            service.get("/product/page", {
+                params: {
+                    page: that.page,
+                    limit: that.limit,
+                    // fileType: that.dataForm.fileType,
+                    search:that.dataForm.title,
+                }
+            }).then((res) => {
+                that.dataListLoading = false;
+                if (res.data.code != 0) {
+                    that.dataList = [];
+                    that.total = 0;
+                    return that.$message.error(res.data.data.msg);
+                }
+                that.dataList = res.data.data.list;
+                that.total = res.data.data.total;
+            }).catch(function () {
+                that.dataListLoading = false;
+            });
+        },
+        // 分页, 每页条数
+        pageSizeChangeHandle: function (val) {
+            that.page = 1;
+            that.limit = val;
+            that.query();
+        },
+        // 分页, 当前页
+        pageCurrentChangeHandle: function (val) {
+            that.page = val;
+            that.query();
+        },
+        getDataList: function () {
+            that.page = 1;
+            that.query();
+        },
+        dialogBeforeClose: function () {
+            that.visible = false;
+            that.$parent.productVisible = false;
+        },
+        batchOptions: function () {
+            that.dataList = that.dataList.map(s => {
+                s.checked = true;
+                return s;
+            })
+            that.checked = true;
+            that.isAllOption = true;
+        },
+        chooseMediaByIndexHandle: function (index) {
+            if (that.isAllOption) { //操作
+                that.$set(that.dataList[index], 'checked', !that.dataList[index].checked);
+                that.$forceUpdate();
+            } else { //选择图片
+                // that.visible = false;
+                // that.onSuccess.call(this, that.dataList[index])
+                that.$set(that.dataList[index], 'checked', !that.dataList[index].checked ? true : false);
+                that.$forceUpdate();
+            }
+        },
+        // 点击确认按钮提交选中商品
+        productHandel() {
+
+            that.visible = false;
+            that.onSuccess.call(this, that.dataList = that.dataList.filter(s => {
+                return s.checked;
+            }))
+        },
+        chooseMediaHandle: function () {
+            //全部操作
+            that.dataList = that.dataList.map(s => {
+                s.checked = that.checked;
+                return s;
+            })
+        },
+        completeMediaHandle: function () {
+            that.dataList = that.dataList.map(s => {
+                s.checked = false;
+                return s;
+            })
+            that.checked = false;
+            that.isAllOption = false;
+        },
+        deleteMediaHandle: function () {
+            if (!that.dataList.some(ss => ss.checked)) {
+                return that.$message.error('未选择文件');
+            }
+            that.$confirm('删除?', '删除', {
+                confirmButtonText: '确认',
+                cancelButtonText: '取消',
+                type: 'warning'
+            }).then(function () {
+                service.delete('/sys/oss', { 'data': that.dataList.filter(item => { return item.checked == true }).map(item => item.id) })
+                    .then(function (res) {
+                        if (res.data.code !== 0) return that.$message.error(res.data.msg);
+                        that.$message({
+                            message: '操作成功',
+                            type: 'success',
+                            duration: 500,
+                            onClose: function () {
+                                that.query();
+                            }
+                        });
+                    }).catch(function () {
+                    });
+            }).catch(function () {
+            });
+        }
+    }
+}
+</script>
+
+<style scoped>
+.clearfix:after {
+    visibility: hidden;
+    display: block;
+    font-size: 0;
+    content: " ";
+    height: 0;
+}
+
+.clearfix:after {
+    content: "";
+    display: table;
+    clear: both;
+}
+
+/* 弹窗 */
+.el-dialog__wrapper .el-dialog .el-dialog__header {
+    padding-top: 16px;
+    padding-bottom: 16px;
+    border-bottom: 1px solid #dcdcdc;
+}
+
+/* 图片素材 */
+.material-wrapper .el-dialog__body {
+    padding: 0 !important;
+}
+
+.material-side {
+    float: left;
+    position: relative;
+    width: 180px;
+    text-align: center;
+    border-right: 1px solid #eaeff4;
+    box-sizing: border-box;
+    padding-right: 20px;
+}
+
+.material-side.image-side {
+    height: 640px;
+}
+
+.pictrue-tabs {
+    width: 160px;
+    height: 50px;
+    line-height: 50px;
+    padding-left: 24px;
+    text-align: left;
+    background: #edf1ff;
+    box-sizing: border-box;
+}
+
+.material-side .side-btns {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    width: 100%;
+    padding-bottom: 14px;
+}
+
+.file-upload {
+    display: inline-block;
+}
+
+.material-side .side-btns .el-button {
+    display: block;
+    width: 132px;
+    margin: 10px auto;
+    border-radius: 16px;
+}
+
+.material-list {
+    width: 940px;
+    box-sizing: border-box;
+    overflow: hidden;
+    margin: auto;
+}
+
+.material-list.image-list {
+    padding: 24px 18px;
+}
+
+.material-list .list-box.image-box {
+    height: 510px;
+}
+
+.material-list .list-box.video-box {
+    height: 450px;
+}
+
+.material-list .list-box .list-item {
+    position: relative;
+    box-sizing: border-box;
+    cursor: pointer;
+}
+
+.material-list .list-box .image-item {
+    float: left;
+    display: block;
+    width: 130px;
+    height: 130px;
+    margin: 0 6px 40px;
+    background: #e0e0e0;
+}
+
+.material-list .list-box .image-item .bg-img {
+    width: 100%;
+    height: 100%;
+    box-sizing: border-box;
+    background-size: contain;
+    background-repeat: no-repeat;
+    background-position: 50%;
+}
+
+.material-list .list-box .video-item {
+    float: left;
+    display: block;
+    width: 130px;
+    height: 130px;
+    margin: 0 6px 40px;
+    background: #e0e0e0;
+}
+
+.material-list .list-box .video-item video {
+    display: block;
+    width: 100%;
+    height: 100%;
+    box-sizing: border-box;
+}
+
+.inline-text-editor input {
+    display: block;
+    width: 100%;
+    height: 20px;
+    margin: 5px 0;
+    line-height: 20px;
+    border: 1px solid transparent;
+    outline: none;
+    font-size: 14px;
+    color: #53586b;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+}
+
+.material-list .list-box .list-item .del-btn {
+    z-index: 10;
+    position: absolute;
+    top: 5px;
+    right: 5px;
+    display: none;
+    width: 14px;
+    height: 14px;
+    color: #fff;
+    font-size: 12px;
+    text-align: center;
+    line-height: 13px;
+    background: rgba(0, 0, 0, .4);
+    border-radius: 18px;
+    cursor: pointer;
+}
+
+.material-list .list-box .list-item:hover .del-btn {
+    display: block;
+}
+
+.material-list .list-box .list-item.active .checked-item {
+    position: absolute;
+    top: 0;
+    left: 0;
+    display: block;
+    height: 40px;
+    width: 40px;
+    background: url(../assets/images/check_gou.png) no-repeat;
+}
+
+.material-list .list-box .list-item.active .bg-img,
+.material-list .list-box .list-item.active video {
+    /* border: 2px solid #409eff; */
+}
+
+.material-list .list-box .video-item .video-info {
+    width: 100%;
+    font-size: 12px;
+    color: #999;
+}
+
+.material-list .list-box .video-item .video-info-left {
+    float: left;
+    width: 50%;
+    text-align: left;
+}
+
+.material-list .list-box .video-item .video-info-right {
+    float: left;
+    width: 50%;
+    text-align: right;
+}
+
+.material-list .list-box .video-item .video-duration {
+    position: absolute;
+    bottom: 8px;
+    right: 8px;
+    padding: 5px 9px;
+    font-size: 12px;
+    text-align: center;
+    color: #fff;
+    background: #000;
+    border-radius: 2px;
+    opacity: .7;
+}
+
+.material-list .list-footer {
+    margin-top: 8px;
+}
+
+.material-list .list-footer .list-ctrl {
+    float: left;
+    width: 230px;
+    height: 32px;
+}
+
+.material-list .list-footer .list-ctrl .el-button {
+    padding: 9px 24px;
+}
+
+.material-list .list-footer .list-ctrl .ctrl-del {
+    margin: 0 6px;
+}
+
+.material-list .list-footer .list-page {
+    float: right;
+    width: 542px;
+    text-align: right;
+}
+</style>

+ 298 - 0
src/components/setting/settingApplicationForm.vue

@@ -0,0 +1,298 @@
+<template>
+    <div class="panel">
+        <div class="panel-header">
+            <h3 class="header-title">{{ data.name }}设置</h3>
+            <a class="el-icon-close close-btn" @click="closeRightTemplateHandle"></a>
+        </div>
+        <div>
+            <el-form label-position="top" ref="form" :model="form" label-width="80px">
+                <el-form-item style="margin-bottom: 0;">
+                    <div class="text-setting">
+                        <span>标题</span>
+                        <span>是否显示
+                            <el-switch size="mini" @change="handleDate" v-model="content.value.title.isShow"
+                                :active-value="true" :inactive-value="false">
+                            </el-switch>
+                        </span>
+                    </div>
+                    <el-input size="mini" v-if="content.value.title.isShow" @input="handleDate"
+                        v-model="content.value.title.value">
+                    </el-input>
+                </el-form-item>
+                <el-form-item style="margin-bottom: 0;" label="数据库名">
+                    <!-- <el-input @input="handleDate" v-model="content.value.database"></el-input> -->
+                    <el-select size="mini" @change="databaseChange" v-model="content.value.database" placeholder="数据库名">
+                        <el-option label="请选择" value=""></el-option>
+                        <el-option :label="item.title" :value="item.id" v-for="item in customFormList" :key="item.id">
+                        </el-option>
+                    </el-select>
+                </el-form-item>
+                <el-form-item style="margin-bottom: 0;" label="按钮名称">
+                    <el-input size="mini" @input="handleDate" v-model="content.value.buttonName"></el-input>
+                </el-form-item>
+                <div>
+                    <el-card style="margin:10px ;" v-for="item, index in content.value.formItemList"
+                        :key="index + '_formitem'">
+                        <div class="form-item">
+                            <div>
+                                <span style="width: 100px;margin-right: 10px;">是否必填</span>
+                                <el-switch size="mini" @change="handleDate" v-model="item.required" :active-value="true"
+                                    :inactive-value="false">
+                                </el-switch>
+                            </div>
+                            <el-button size="mini" type="danger" icon="el-icon-delete" circle v-if="content.value.formItemList.length>1"
+                                @click="deleteItem(index, item)"></el-button>
+                        </div>
+                        <div class="form-item">
+                            <span style="width: 100px;">字段名</span>
+                            <el-input class="flex-1" size="mini" @input="handleDate" v-model="item.label">
+                            </el-input>
+                        </div>
+                        <div class="form-item">
+                            <span style="width: 100px;">数据库字段名</span>
+                            <!-- <el-input class="flex-1" size="mini" @input="handleDate" v-model="item.databaseLabel">
+                            </el-input> -->
+                            <el-select class="flex-1" size="mini" @change="(val) => { databaseLabelChange(val, index) }"
+                                v-model="item.databaseLabel" placeholder="数据库字段名">
+                                <el-option :label="formColumnList.length > 0 ? '请选择' : '请先选择数据库名'" value=""></el-option>
+                                <el-option :label="item.fieldName" :value="item.id" v-for="item, index in formColumnList"
+                                    :key="item.id + '_column_' + index"></el-option>
+                            </el-select>
+                        </div>
+                        <div class="form-item">
+                            <span style="width: 100px;">表单类型</span>
+                            <el-select disabled class="flex-1" size="mini" @change="(val) => { changeType(val, index) }"
+                                v-model="item.type" placeholder="表单类型">
+                                <el-option label="文本" :value="1"></el-option>
+                                <el-option label="单选框" :value="2"></el-option>
+                                <el-option label="多选框" :value="3"></el-option>
+                                <el-option label="文本域" :value="4"></el-option>
+                                <el-option label="下拉单选框" :value="5"></el-option>
+                                <el-option label="富文本" :value="6"></el-option>
+                                <el-option label="图片" :value="7"></el-option>
+                                <el-option label="时间格式" :value="8"></el-option>
+                                <el-option label="文本" :value="9"></el-option>
+                            </el-select>
+                        </div>
+                        <div v-if="item.type == 'select'">
+                            <el-table :data="item.option">
+                                <el-table-column label="选项标签">
+                                    <template slot-scope="scope">
+                                        <el-input size="mini" @input="handleDate"
+                                            v-model="item.option[scope.$index].label"></el-input>
+                                    </template>
+                                </el-table-column>
+                                <el-table-column label="选项值">
+                                    <template slot-scope="scope">
+                                        <el-input size="mini" @input="handleDate"
+                                            v-model="item.option[scope.$index].value"></el-input>
+                                    </template>
+                                </el-table-column>
+                                <el-table-column label="操作" width="80">
+                                    <template slot="header" slot-scope="scope">
+                                        <el-button type="text" size="mini"
+                                            @click="addOptionItem(item.option, scope.$index)">添加选项</el-button>
+                                    </template>
+                                    <template slot-scope="scope">
+                                        <el-button size="mini" type="danger" icon="el-icon-delete" circle
+                                            @click="deleteOptionItem(item.option, scope.$index)"></el-button>
+                                    </template>
+                                </el-table-column>
+                            </el-table>
+                        </div>
+                        <div class="btnDiv">
+                            <el-button size="mini" type="text" icon="el-icon-plus" @click="addItem(index)">添加
+                            </el-button>
+                        </div>
+                    </el-card>
+                </div>
+            </el-form>
+
+        </div>
+    </div>
+</template>
+
+<script>
+import service from '@/utlis/axios'
+export default {
+    name: 'settingApplicationForm',
+    props: ['data'],
+    data() {
+        return {
+            content: JSON.parse(JSON.stringify(this.data)),
+            form: {},
+            customFormList: [],
+            formColumnList: []
+        }
+    },
+    created() {
+        this.getCustomForm()
+        if(this.content.value.database){
+            this.getFormColumn(this.content.value.database)
+        }
+    },
+    methods: {
+        handleDate() {
+            this.$emit('updataContent', this.content)
+        },
+        closeRightTemplateHandle() {
+            this.$emit('closeRightTemplateHandle', false)
+        },
+        //选择数据库名
+        databaseChange(val) {
+            // this.getFormColumn(this.content.value.database)
+            if (val != this.content.value.database) {
+                this.content.value.formItemList.forEach(item => {
+                    item.databaseLabel = ''
+                    item.type = 1
+                    delete item.option
+                });
+            }
+            this.handleDate()
+            this.getFormColumn(this.content.value.database)
+        },
+        // 选择输入框类型(input 下拉 select 选择)
+        // 字段类型 1、文本 2、单选框 3、多选框 4、文本域 5、下拉单选框 6、富文本 7、图片 8、时间格式
+        changeType(val, index) {
+            if (val == '1') {
+                delete this.content.value.formItemList[index].option
+            } else if (val == '5') {
+                delete this.content.value.formItemList[index].option
+                this.content.value.formItemList[index].option = []
+            }
+        },
+        // 选择数据库字段名
+        databaseLabelChange(val, index) {
+            let typeVal = this.formColumnList.filter(item => { return item.id == val })
+            this.content.value.formItemList[index].type = typeVal[0].fieldType
+            this.changeType(typeVal[0].fieldType, index)
+            this.handleDate()
+        },
+        // 删除表单项
+        deleteItem(index, row) {
+            this.content.value.formItemList.splice(index, 1)
+            this.handleDate()
+        },
+        // 添加表单项
+        addItem(index) {
+            let obj = { label: '', databaseLabel: '', required: true };
+            this.content.value.formItemList.splice(index + 1, 0, obj)
+            this.handleDate()
+        },
+        // 添加下拉框选项
+        addOptionItem(list, index) {
+            list.push({ label: '', value: '' })
+            this.handleDate()
+        },
+        // 删除下拉框选项
+        deleteOptionItem(list, index) {
+            list.splice(index, 1)
+            this.handleDate()
+        },
+        // 获取表单信息
+        getCustomForm() {
+            service.get("/custom/form/list").then((res) => {
+                if (res.data.code != 0) {
+                    return that.$message.error(res.data.data.msg);
+                }
+                this.customFormList = res.data.data;
+            }).catch(function () {
+            });
+        },
+        // 获取表单下的字段
+        getFormColumn(formId) {
+            service.get("/custom/form/column/list?formId=" + formId).then((res) => {
+                if (res.data.code != 0) {
+                    return that.$message.error(res.data.data.msg);
+                }
+                this.formColumnList = res.data.data;
+            }).catch(function () {
+            });
+        }
+
+    }
+}
+</script>
+
+<style  scoped>
+.panel {
+    padding: 0 10px;
+}
+
+.panel .panel-header {
+    position: relative;
+    height: 40px;
+    line-height: 40px;
+    margin-left: 8px;
+    margin-right: 8px;
+    vertical-align: middle;
+    border-bottom: 1px solid #dcdcdc;
+    box-sizing: border-box;
+    z-index: 10;
+}
+
+.panel .panel-header .header-title {
+    padding-left: 5px;
+    font-size: 14px;
+    color: #29304e;
+    position: relative;
+}
+
+.panel .panel-header .header-title:before {
+    content: "";
+    position: absolute;
+    top: 50%;
+    left: 0;
+    transform: translateY(-50%);
+    width: 3px;
+    height: 18px;
+    background: #1890ff;
+    opacity: 1;
+    border-radius: 2px;
+}
+
+.panel .panel-header .close-btn {
+    position: absolute;
+    top: 12px;
+    right: 0;
+    border: none;
+    outline: none;
+    cursor: pointer;
+    color: #999;
+    font-weight: 700;
+}
+
+.panel .panel-body {
+    position: absolute;
+    top: 40px;
+    bottom: 0;
+    width: 100%;
+    overflow-y: auto;
+}
+
+.btnDiv {
+    text-align: center;
+    margin-top: 5px;
+}
+
+.text-setting {
+    display: flex;
+    justify-content: space-between;
+    margin: 10px 0;
+}
+
+.form-item {
+    display: flex;
+    margin: 10px 0;
+    align-items: center;
+    justify-content: space-between;
+}
+
+.form-item span {
+    font-size: 14px;
+}
+
+.flex-1 {
+    flex: 1;
+}
+</style>

+ 197 - 0
src/components/setting/settingBanner.vue

@@ -0,0 +1,197 @@
+<template>
+    <div class="panel">
+        <div class="panel-header">
+            <h3 class="header-title">{{ data.name }}设置</h3>
+            <a class="el-icon-close close-btn" @click="closeRightTemplateHandle"></a>
+        </div>
+        <div>
+            <!-- 计数 -->
+            <div class="self-number">
+                <el-button-group>
+                    <el-button class="the-btn" size="mini" @click="numOption('-')"><i class="el-icon-minus"></i>
+                    </el-button>
+                    <el-button class="the-btn" size="mini" v-for="number, index in content.value.imageList" :key="index"
+                        @click="changeNum(index)" :class="index == btnActIndex ? 'btn-active' : ''">{{ index+1 }}
+                    </el-button>
+                    <el-button class="the-btn" size="mini" @click="numOption('+')"><i class="el-icon-plus"></i>
+                    </el-button>
+                </el-button-group>
+            </div>
+            <!-- 轮播 -->
+            <el-carousel ref="carousel" @change="carouselChange" :autoplay="false" height="150px" trigger="click"
+                arrow="never">
+                <el-carousel-item v-for="item, index in content.value.imageList" :key="index">
+                    <img v-if="item.src" :src="item.src">
+                    <img v-else src="../../assets/images/defaultimg.jpg" />
+                </el-carousel-item>
+            </el-carousel>
+            <!-- 上传图片 -->
+            <div class="updataBtn">
+                <el-button style="width:100%" type="primary" round @click="updataImage">上传图片</el-button>
+            </div>
+        </div>
+        <materialManage v-if="materialVisible" :on-success="chooseImageHandle" :file-type="fileType" item-or-src="item">
+        </materialManage>
+    </div>
+</template>
+
+<script>
+import materialManage from '@/components/materialManage'
+export default {
+    components: {
+        materialManage
+    },
+    name: 'settingBanner',
+    props: ['data'],
+    data() {
+        return {
+            btnActIndex: 0,
+            content: JSON.parse(JSON.stringify(this.data)),
+            materialVisible: false,
+            fileType: 1
+        }
+    },
+    methods: {
+        handleDate() {
+            this.$emit('updataContent', this.content)
+        },
+        closeRightTemplateHandle() {
+            this.$emit('closeRightTemplateHandle', false)
+        },
+        numOption(op) {
+            if (op == '-') {
+                if (this.content.value.imageList.length == 1) { }
+                else this.content.value.imageList.pop()
+            }
+            if (op == '+') {
+                this.content.value.imageList.push({ src: '' })
+            }
+            this.handleDate()
+            this.$nextTick(()=>{
+                this.changeNum(this.content.value.imageList.length-1)
+            })
+        },
+        changeNum(index) {
+            this.btnActIndex = index
+            this.$refs.carousel.setActiveItem(index)
+        },
+        carouselChange(index) {
+            this.btnActIndex = index
+        },
+        // 上传图片
+        updataImage() {
+            this.materialVisible = true
+        },
+        chooseImageHandle(val) {
+            this.content.value.imageList[this.btnActIndex].src = val.url
+            this.materialVisible = false
+            this.handleDate()
+        }
+    }
+}
+</script>
+
+<style  scoped>
+.panel {
+    padding: 0 10px;
+}
+
+.panel .panel-header {
+    position: relative;
+    height: 40px;
+    line-height: 40px;
+    margin-left: 8px;
+    margin-right: 8px;
+    vertical-align: middle;
+    border-bottom: 1px solid #dcdcdc;
+    box-sizing: border-box;
+    z-index: 10;
+}
+
+.panel .panel-header .header-title {
+    padding-left: 5px;
+    font-size: 14px;
+    color: #29304e;
+    position: relative;
+}
+
+.panel .panel-header .header-title:before {
+    content: "";
+    position: absolute;
+    top: 50%;
+    left: 0;
+    transform: translateY(-50%);
+    width: 3px;
+    height: 18px;
+    background: #1890ff;
+    opacity: 1;
+    border-radius: 2px;
+}
+
+.panel .panel-header .close-btn {
+    position: absolute;
+    top: 12px;
+    right: 0;
+    border: none;
+    outline: none;
+    cursor: pointer;
+    color: #999;
+    font-weight: 700;
+}
+
+.panel .panel-body {
+    position: absolute;
+    top: 40px;
+    bottom: 0;
+    width: 100%;
+    overflow-y: auto;
+}
+
+.the-btn:disabled {
+    cursor: not-allowed !important;
+}
+
+.the-btn {
+    margin-right: 8px !important;
+    width: 30px;
+    height: 30px;
+    padding: 0 6px;
+    background: #f0f2f5;
+    opacity: 1;
+    border-radius: 2px !important;
+    color: #606266;
+    transition: all .5s;
+}
+
+.self-number {
+    margin: 10px 10px;
+}
+
+.self-number .btn-active {
+    background: #1989fa !important;
+    color: #fff !important;
+}
+
+/* .el-carousel__item h3 {
+    color: #475669;
+    font-size: 14px;
+    opacity: 0.75;
+    line-height: 150px;
+    margin: 0;
+}
+
+.el-carousel__item:nth-child(2n) {
+    background-color: #99a9bf;
+}
+
+.el-carousel__item:nth-child(2n+1) {
+    background-color: #d3dce6;
+} */
+img{
+    width: 100%;
+}
+.updataBtn {
+    margin: 10px auto;
+    width: 80%;
+}
+</style>

+ 125 - 0
src/components/setting/settingCustomerService.vue

@@ -0,0 +1,125 @@
+<template>
+    <div class="panel">
+        <div class="panel-header">
+            <h3 class="header-title">{{ data.name }}设置</h3>
+            <a class="el-icon-close close-btn" @click="closeRightTemplateHandle"></a>
+        </div>
+        <div>
+            <div class="text-setting">
+                <span>客服类型</span>
+                <el-select size="mini" @change="handleDate" v-model="content.value.type" placeholder="表单类型">
+                    <el-option label="小程序客服" value="0"></el-option>
+                    <el-option label="企微客服" value="1"></el-option>
+                    <el-option label="第三方客服" value="2"></el-option>
+                </el-select>
+            </div>
+            <div class="input-item" v-if="content.value.type == 1">
+                <div>企业ID</div>
+                <el-input type="textarea" placeholder="填写企业ID" :autosize="{ minRows: 1 }" @input="handleDate"
+                    v-model="content.value.id">
+                </el-input>
+            </div>
+            <div class="input-item" v-if="content.value.type == 1||content.value.type ==2">
+                <div>跳转地址</div>
+                <el-input type="textarea" placeholder="填写跳转地址" :autosize="{ minRows: 2 }" @input="handleDate"
+                    v-model="content.value.target">
+                </el-input>
+            </div>
+            <!-- <div class="input-item">
+                <div>文本</div>
+                <el-input type="textarea" placeholder="填写文本" :autosize="{ minRows: 1 }" @input="handleDate"
+                    v-model="content.value.text">
+                </el-input>
+            </div> -->
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'settingCustomerService',
+    props: ['data'],
+    data() {
+        return {
+            content: JSON.parse(JSON.stringify(this.data)),
+        }
+    },
+    methods: {
+        handleDate() {
+            this.$emit('updataContent', this.content)
+        },
+        closeRightTemplateHandle() {
+            this.$emit('closeRightTemplateHandle', false)
+        }
+    }
+}
+</script>
+
+<style  scoped>
+.panel {
+    padding: 0 10px;
+}
+
+.panel .panel-header {
+    position: relative;
+    height: 40px;
+    line-height: 40px;
+    margin-left: 8px;
+    margin-right: 8px;
+    vertical-align: middle;
+    border-bottom: 1px solid #dcdcdc;
+    box-sizing: border-box;
+    z-index: 10;
+}
+
+.panel .panel-header .header-title {
+    padding-left: 5px;
+    font-size: 14px;
+    color: #29304e;
+    position: relative;
+}
+
+.panel .panel-header .header-title:before {
+    content: "";
+    position: absolute;
+    top: 50%;
+    left: 0;
+    transform: translateY(-50%);
+    width: 3px;
+    height: 18px;
+    background: #1890ff;
+    opacity: 1;
+    border-radius: 2px;
+}
+
+.panel .panel-header .close-btn {
+    position: absolute;
+    top: 12px;
+    right: 0;
+    border: none;
+    outline: none;
+    cursor: pointer;
+    color: #999;
+    font-weight: 700;
+}
+
+.panel .panel-body {
+    position: absolute;
+    top: 40px;
+    bottom: 0;
+    width: 100%;
+    overflow-y: auto;
+}
+
+.text-setting {
+    display: flex;
+    justify-content: space-between;
+    margin: 10px 0;
+}
+.input-item{
+    margin: 10px 0;
+}
+.input-item div{
+    margin-bottom: 10px;
+}
+</style>

+ 120 - 0
src/components/setting/settingImage.vue

@@ -0,0 +1,120 @@
+<template>
+    <div class="panel">
+        <div class="panel-header">
+            <h3 class="header-title">{{ data.name }}设置</h3>
+            <a class="el-icon-close close-btn" @click="closeRightTemplateHandle"></a>
+        </div>
+        <div class="image-bar">
+            <img v-if="content.value.src" :src="content.value.src"/>
+            <img v-else src="../../assets/images/defaultimg.jpg" />
+        </div>
+        <!-- 上传图片 -->
+        <div class="updataBtn">
+            <el-button style="width:100%" type="primary" round @click="updataImage">上传图片</el-button>
+        </div>
+        <materialManage v-if="materialVisible" :on-success="chooseImageHandle" :file-type="fileType" item-or-src="item">
+        </materialManage>
+    </div>
+</template>
+
+<script>
+import materialManage from '@/components/materialManage'
+export default {
+    components: {
+        materialManage
+    },
+    name: 'settingImage',
+    props: ['data', 'className'],
+    data() {
+        return {
+            content: JSON.parse(JSON.stringify(this.data)),
+            materialVisible: false,
+            fileType: 1
+        }
+    },
+    methods: {
+        handleDate() {
+            this.$emit('updataContent', this.content)
+        },
+        closeRightTemplateHandle() {
+            this.$emit('closeRightTemplateHandle', false)
+        },
+        // 上传图片
+        updataImage() {
+            this.materialVisible = true
+        },
+        chooseImageHandle(val) {
+            this.content.value.src = val.url
+            this.materialVisible = false
+            this.handleDate()
+        }
+    }
+}
+</script>
+
+<style  scoped>
+.panel {
+    padding: 0 10px;
+}
+
+.panel .panel-header {
+    position: relative;
+    height: 40px;
+    line-height: 40px;
+    margin-left: 8px;
+    margin-right: 8px;
+    vertical-align: middle;
+    border-bottom: 1px solid #dcdcdc;
+    box-sizing: border-box;
+    z-index: 10;
+}
+
+.panel .panel-header .header-title {
+    padding-left: 5px;
+    font-size: 14px;
+    color: #29304e;
+    position: relative;
+}
+
+.panel .panel-header .header-title:before {
+    content: "";
+    position: absolute;
+    top: 50%;
+    left: 0;
+    transform: translateY(-50%);
+    width: 3px;
+    height: 18px;
+    background: #1890ff;
+    opacity: 1;
+    border-radius: 2px;
+}
+
+.panel .panel-header .close-btn {
+    position: absolute;
+    top: 12px;
+    right: 0;
+    border: none;
+    outline: none;
+    cursor: pointer;
+    color: #999;
+    font-weight: 700;
+}
+
+.panel .panel-body {
+    position: absolute;
+    top: 40px;
+    bottom: 0;
+    width: 100%;
+    overflow-y: auto;
+}
+.image-bar{
+    text-align: center;
+    margin: 10px 0;
+}
+img {
+    width: 100%;
+}
+.updataBtn{
+    padding: 0px 40px;
+}
+</style>

+ 362 - 0
src/components/setting/settingProduct.vue

@@ -0,0 +1,362 @@
+<template>
+    <div class="product-content panel">
+        <div class="panel-header">
+            <h3 class="header-title">{{ content.name }}设置</h3>
+            <a class="el-icon-close close-btn" @click="closeRightTemplateHandle"></a>
+        </div>
+        <div class="tab">
+            <span v-for="(item, index) in 3" :key="index" @click="changeLayoutNum(index)"
+                :class="{ active: index + 1 == content.value.layoutNum }"><i class="el-icon-s-data"></i> {{ index + 1
+                }}</span>
+        </div>
+        <p class="tit">商品列表</p>
+        <el-button class="add-btn" type="primary" @click="toggleSearchPopup"><i class="el-icon-plus"></i> 添加商品
+        </el-button>
+        <template v-if="content.value.productList && content.value.productList.length > 0">
+            <ul class="list" v-if="content.value.productList && content.value.productList.length > 0">
+                <li class="item" v-for="(item, index) in content.value.productList" :key="index">
+                    <img :src="item.pic">
+                    <i class="el-icon-error" @click="deleteItem(index)"></i>
+                </li>
+            </ul>
+        </template>
+
+        <div class="options">
+            <el-form label-width="100px">
+                <el-form-item label="划线价">
+                    <el-switch v-model="content.value.showOriginalPrice" :active-value="true" :inactive-value="false"
+                        @change="handleDate">
+                    </el-switch>
+                </el-form-item>
+            </el-form>
+        </div>
+
+        <el-dialog title="添加商品" :visible.sync="show" @close="close">
+            <el-form label-width="100px">
+                <el-form-item label="选择商品">
+                    <el-select v-model="selectProduct" filterable remote reserve-keyword placeholder="请输入商品名称"
+                        :remote-method="searchProductList" @change="addProduct" :loading="loading">
+                        <el-option v-for="item in productList" :key="item.productId" :label="item.productName"
+                            :value-key="item.productName" :value="item">
+                        </el-option>
+                    </el-select>
+                </el-form-item>
+                <el-form-item>
+                    <el-button type="primary" @click="confirm">确定</el-button>
+                </el-form-item>
+            </el-form>
+        </el-dialog>
+
+        <!-- 商品导入组件 -->
+        <productManage v-if="productVisible" :on-success="chooseProductHandle">
+        </productManage>
+    </div>
+</template>
+
+<script>
+import productManage from '@/components/productManage.vue'
+export default {
+    name: 'settingProduct',
+    components: {
+        productManage
+    },
+    props: ['data'],
+    data() {
+        return {
+            content: JSON.parse(JSON.stringify(this.data)),
+            list: {},
+            productList: [],
+            loading: false,
+            show: false,
+
+            selectItem: null,
+            selectProduct: '',
+
+            options: {
+                originalPrice: '划线价',
+                goodRatio: '好评率',
+                volumeStr: '销量数'
+            },
+            loadingOption: false,
+
+            productVisible: false
+        }
+    },
+    mounted() {
+    },
+    // watch: {
+    //     data: {
+    //         deep: true,
+    //         handler(val) {
+    //             this.content = val;
+    //         },
+    //     },
+    // },
+    methods: {
+        handleDate() {
+            this.$emit('updataContent', this.content)
+        },
+        closeRightTemplateHandle() {
+            this.$emit('closeRightTemplateHandle', false)
+        },
+
+        // 改变商品排列数量
+        changeLayoutNum(index) {
+            this.content.value.layoutNum = index + 1
+            this.handleDate()
+        },
+
+        deleteItem(index) {
+            this.content.value.productList.splice(index, 1)
+            this.handleDate()
+        },
+        // 搜索商品
+        searchProductList(productName) {
+            this.productList = productList
+        },
+        confirm() {
+            this.content.value.productList.push(this.selectItem)
+            this.close()
+            this.handleDate()
+        },
+        // 打开商品添加弹框
+        toggleSearchPopup() {
+            this.productVisible = true
+            // this.show = true
+        },
+        // 关闭商品添加弹框
+        close() {
+            this.show = false
+            this.selectItem = null
+            this.selectProduct = ''
+        },
+        addProduct(data) {
+            this.selectItem = data
+        },
+        // 选择商品后的回调
+        chooseProductHandle(val){
+            this.productVisible = false
+            val.forEach(item => {
+                this.content.value.productList.push(item)
+            });
+            this.handleDate()
+        }
+    }
+}
+// 模拟产品列表
+var productList = [{
+    "productId": 3601,
+    "productName": "驼大大新疆正宗骆驼奶粉初乳骆驼乳粉蓝罐礼盒装120g*4罐",
+    "productImg": "https://img.quanminyanxuan.com/excel/f6860885547648d9996474bbf21fdca9.jpg",
+    "productPrice": 299,
+    "originalPrice": 598,
+    "volumeStr": "741",
+    "goodRatio": 98
+}, {
+    "productId": 3268,
+    "productName": "百合28件套新骨质瓷餐具",
+    "productImg": "https://img.quanminyanxuan.com/excel/185e7365f65543f2b4ebc67036d6a78f.jpg",
+    "productPrice": 370,
+    "originalPrice": 1388,
+    "volumeStr": "400",
+    "goodRatio": 99
+}, {
+    "productId": 3343,
+    "productName": "和商臻品槐花蜜250克/瓶",
+    "productImg": "https://img.quanminyanxuan.com/excel/4626c8c628d04935b0262d04991416b2.jpg",
+    "productPrice": 34.5,
+    "originalPrice": 72,
+    "volumeStr": "258",
+    "goodRatio": 98
+}, {
+    "productId": 3330,
+    "productName": "鲍参翅肚浓羹350g袋装",
+    "productImg": "https://img.quanminyanxuan.com/excel/58a0c968dc7d42c3ac21e09d1862aa6f.jpg",
+    "productPrice": 75,
+    "originalPrice": 128,
+    "volumeStr": "258",
+    "goodRatio": 98
+},]
+</script>
+
+<style lang="scss" scoped>
+.panel {
+    padding: 0 10px;
+}
+
+.panel .panel-header {
+    position: relative;
+    height: 40px;
+    line-height: 40px;
+    margin-left: 8px;
+    margin-right: 8px;
+    vertical-align: middle;
+    border-bottom: 1px solid #dcdcdc;
+    box-sizing: border-box;
+    z-index: 10;
+}
+
+.panel .panel-header .header-title {
+    padding-left: 5px;
+    font-size: 14px;
+    color: #29304e;
+    position: relative;
+}
+
+.panel .panel-header .header-title:before {
+    content: "";
+    position: absolute;
+    top: 50%;
+    left: 0;
+    transform: translateY(-50%);
+    width: 3px;
+    height: 18px;
+    background: #1890ff;
+    opacity: 1;
+    border-radius: 2px;
+}
+
+.panel .panel-header .close-btn {
+    position: absolute;
+    top: 12px;
+    right: 0;
+    border: none;
+    outline: none;
+    cursor: pointer;
+    color: #999;
+    font-weight: 700;
+}
+
+.product-content {
+    padding: 0 15px;
+}
+
+.product-content h2 {
+    font-size: 16px;
+    color: #333;
+}
+
+.product-content .tab {
+    display: flex;
+    justify-content: space-around;
+    border: 1px solid #ddd;
+    border-radius: 6px;
+    margin-top: 10px;
+}
+
+.product-content .tab span {
+    width: 33.33%;
+    text-align: center;
+    font-size: 14px;
+    color: #666;
+    display: block;
+    height: 36px;
+    line-height: 36px;
+    cursor: pointer;
+}
+
+.product-content .tab span.active {
+    color: #fff;
+    background: #409eff;
+    border-radius: 2px;
+}
+
+.product-content .tab span:nth-of-type(2) {
+    border-left: 1px solid #ddd;
+    border-right: 1px solid #ddd;
+}
+
+
+.product-content .tit {
+    text-align: center;
+    font-size: 12px;
+    color: #666;
+    margin: 18px 0;
+    padding-bottom: 10px;
+    border-bottom: 1px dashed #ddd;
+}
+
+.product-content .add-btn {
+    width: calc(100% - 30px);
+    height: 34px;
+    line-height: 34px;
+    padding: 0;
+    font-size: 12px;
+    margin-left: 15px;
+    margin-top: 5px;
+}
+
+.product-content .list {
+    display: flex;
+    flex-wrap: wrap;
+    padding: 12px;
+    margin: 0;
+}
+
+.product-content .list .item {
+    width: 70px;
+    height: 70px;
+    border-radius: 6px;
+    margin: 4px;
+    position: relative;
+    transition: all .3s;
+    list-style: none;
+}
+
+.product-content .list .item img {
+    width: 100%;
+    height: 100%;
+    border-radius: 4px;
+}
+
+.product-content .list .item i {
+    position: absolute;
+    top: -6px;
+    right: -6px;
+    cursor: pointer;
+    opacity: 0;
+    transition: all .3s;
+    color: red;
+}
+
+.product-content .list .item::before {
+    content: '';
+    height: 100%;
+    width: 100%;
+    position: absolute;
+    top: 0;
+    right: 0;
+    background: rgba(0, 0, 0, 0.4);
+    border-radius: 4px;
+    opacity: 0;
+    transition: all .3s;
+}
+
+.product-content .list .item:hover {
+    cursor: grab;
+}
+
+.product-content .list .item:hover::before,
+.product-content .list .item:hover i {
+    opacity: 1;
+}
+
+.product-content .options {
+    padding: 15px;
+    border-radius: 6px;
+}
+
+.product-content .options .el-form {
+    background: #f7f8f9;
+    overflow: hidden;
+    padding: 10px 0;
+}
+
+.product-content .options .el-form .el-form-item {
+    margin: 0;
+}
+
+.product-content .options .el-form .el-form-item label {
+    font-size: 12px;
+}
+</style>

+ 101 - 0
src/components/setting/settingText.vue

@@ -0,0 +1,101 @@
+<template>
+    <div class="panel">
+        <div class="panel-header">
+            <h3 class="header-title">{{ data.name }}设置</h3>
+            <a class="el-icon-close close-btn" @click="closeRightTemplateHandle"></a>
+        </div>
+        <div>
+            <div class="text-setting">
+                <span>编辑内容</span>
+                <span >是否为标题
+                    <el-switch size="mini" @change="handleDate" v-model="content.value.isTitle" :active-value="true" :inactive-value="false">
+                    </el-switch>
+                </span>
+            </div>
+            <el-input type="textarea" :autosize="{ minRows: 2}" @input="handleDate" v-model="content.value.content"></el-input>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'settingText',
+    props: ['data', 'className'],
+    data() {
+        return {
+            content: JSON.parse(JSON.stringify(this.data)),
+        }
+    },
+    methods: {
+        handleDate() {
+            this.$emit('updataContent', this.content)
+        },
+        closeRightTemplateHandle() {
+            this.$emit('closeRightTemplateHandle', false)
+        }
+    }
+}
+</script>
+
+<style  scoped>
+.panel {
+    padding: 0 10px;
+}
+
+.panel .panel-header {
+    position: relative;
+    height: 40px;
+    line-height: 40px;
+    margin-left: 8px;
+    margin-right: 8px;
+    vertical-align: middle;
+    border-bottom: 1px solid #dcdcdc;
+    box-sizing: border-box;
+    z-index: 10;
+}
+
+.panel .panel-header .header-title {
+    padding-left: 5px;
+    font-size: 14px;
+    color: #29304e;
+    position: relative;
+}
+
+.panel .panel-header .header-title:before {
+    content: "";
+    position: absolute;
+    top: 50%;
+    left: 0;
+    transform: translateY(-50%);
+    width: 3px;
+    height: 18px;
+    background: #1890ff;
+    opacity: 1;
+    border-radius: 2px;
+}
+
+.panel .panel-header .close-btn {
+    position: absolute;
+    top: 12px;
+    right: 0;
+    border: none;
+    outline: none;
+    cursor: pointer;
+    color: #999;
+    font-weight: 700;
+}
+
+.panel .panel-body {
+    position: absolute;
+    top: 40px;
+    bottom: 0;
+    width: 100%;
+    overflow-y: auto;
+}
+
+.text-setting {
+    display: flex;
+    justify-content: space-between;
+    margin: 10px 0;
+}
+</style>

+ 5 - 1
src/main.js

@@ -2,9 +2,13 @@ import Vue from 'vue'
 import App from './App.vue'
 import router from './router'
 import store from './store'
+import ElementUI from 'element-ui'
+import axios from 'axios'
+import 'element-ui/lib/theme-chalk/index.css'
 
 Vue.config.productionTip = false
-
+Vue.use(ElementUI)
+Vue.prototype.$axios = axios
 new Vue({
   router,
   store,

+ 13 - 14
src/router/index.js

@@ -1,23 +1,22 @@
 import Vue from 'vue'
 import VueRouter from 'vue-router'
-import HomeView from '../views/HomeView.vue'
 
 Vue.use(VueRouter)
 
 const routes = [
-  {
-    path: '/',
-    name: 'home',
-    component: HomeView
-  },
-  {
-    path: '/about',
-    name: 'about',
-    // route level code-splitting
-    // this generates a separate chunk (about.[hash].js) for this route
-    // which is lazy-loaded when the route is visited.
-    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
-  }
+  // {
+  //   path: '/',
+  //   name: 'home',
+  //   component: HomeView
+  // },
+  // {
+  //   path: '/about',
+  //   name: 'about',
+  //   // route level code-splitting
+  //   // this generates a separate chunk (about.[hash].js) for this route
+  //   // which is lazy-loaded when the route is visited.
+  //   component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
+  // }
 ]
 
 const router = new VueRouter({

+ 63 - 0
src/utlis/axios.js

@@ -0,0 +1,63 @@
+import axios from "axios";
+import {getCookie} from '@/utlis/utli'
+const service = axios.create({
+  withCredentials: true,
+  baseURL: 'http://mptest.tongyu99.com',
+  // baseURL: 'http://mall.zhiqiyun.com',
+  // baseURL: '/api',
+  // baseURL: process.env.VUE_APP_BASEURL,
+  timeout: 1000 * 180,
+  headers: {
+    "content-type": 'text/plain;charset=utf-8',
+    'Accept-Language': 'zh-CN'
+  }
+});
+
+// // 请求拦截
+// service.interceptors.request.use(
+//   function (config) {
+//     // config.headers["Accept-Language"] = "zh-CN";
+//     // config.headers["content-type"] = "text/plain";
+//     // const js_auth_token = VueCookie.get("js_auth_token");
+//     // config.headers["jsdk_api_info"] = js_auth_token || "NEW_JS_API";
+//     // 默认参数
+//     var defaults = {};
+//     // 防止缓存,GET请求默认带_t参数
+//     if (config.method === "get") {
+//       config.params = _.merge({}, config.params, { _t: new Date().getTime() });
+//     }
+//     if (_.isPlainObject(config.params)) {
+//       config.params = _.merge({}, defaults, config.params);
+//     }
+//     if (_.isPlainObject(config.data)) {
+//       config.data = _.merge({}, defaults, config.data);
+//       if (
+//         /^application\/x-www-form-urlencoded/.test(
+//           config.headers["content-type"]
+//           || /^text\/plain/.test(config.headers["content-type"])
+//         )
+//       ) {
+//         config.data = Qs.stringify(config.data);
+//       }
+//     }
+//     return config;
+//   },
+//   function (error) {
+//     return Promise.reject(error);
+//   }
+// );
+// // 响应拦截
+// service.interceptors.response.use(
+//   function (response) {
+//     if (response.data.code === 401) {
+//       win.location.href = process.env.VUE_APP_URL;
+//       return Promise.reject(response.data.msg);
+//     }
+//     return /<[^>]+>/g.test(response.data) ? false : response;
+//   },
+//   function (error) {
+//     return Promise.reject(error);
+//   }
+// );
+
+export default service;

+ 23 - 0
src/utlis/utli.js

@@ -0,0 +1,23 @@
+export function setCookie (cname, cvalue, exdays) {
+    var d = new Date();
+    d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
+    var expires = "expires=" + d.toUTCString();
+    document.cookie = cname + "=" + cvalue + "; " + expires;
+}
+//获取cookie
+export function getCookie (cname) {
+    var name = cname + "=";
+    var ca = document.cookie.split(';');
+    for (var i = 0; i < ca.length; i++) {
+        var c = ca[i];
+        while (c.charAt(0) == ' ') c = c.substring(1);
+        if (c.indexOf(name) != -1) {
+            return c.substring(name.length, c.length);
+        }
+    }
+    return "";
+}
+//清除cookie
+export function clearCookie (name) {
+    this.setCookie(name, "", -1);
+}

+ 0 - 5
src/views/AboutView.vue

@@ -1,5 +0,0 @@
-<template>
-  <div class="about">
-    <h1>This is an about page</h1>
-  </div>
-</template>

+ 0 - 18
src/views/HomeView.vue

@@ -1,18 +0,0 @@
-<template>
-  <div class="home">
-    <img alt="Vue logo" src="../assets/logo.png">
-    <HelloWorld msg="Welcome to Your Vue.js App"/>
-  </div>
-</template>
-
-<script>
-// @ is an alias to /src
-import HelloWorld from '@/components/HelloWorld.vue'
-
-export default {
-  name: 'HomeView',
-  components: {
-    HelloWorld
-  }
-}
-</script>

+ 16 - 1
vue.config.js

@@ -1,4 +1,19 @@
 const { defineConfig } = require('@vue/cli-service')
 module.exports = defineConfig({
-  transpileDependencies: true
+  transpileDependencies: true,
 })
+module.exports = {
+  publicPath: '',
+  // devServer: {
+  //   proxy: {
+  //     '/api': {
+  //       target: 'http://mptest.tongyu99.com',
+  //       changeOrigin: true,
+  //       pathRewrite: {
+  //         '^/api': ''
+  //       }
+  //     }
+  //   }
+  // }
+
+}