Jelajahi Sumber

新增:页面设计器操作工具栏

萤火科技 1 tahun lalu
induk
melakukan
cc645a08cd

TEMPAT SAMPAH
src/assets/img/topNavBlack_new.png


TEMPAT SAMPAH
src/assets/img/topNavWhite_new.png


+ 3 - 3
src/global.less

@@ -4,14 +4,14 @@
 
 
 // 滚动条样式
 // 滚动条样式
 ::-webkit-scrollbar {
 ::-webkit-scrollbar {
-  width: 6px;
-  height: 6px;
+  width: 5px;
+  height: 5px;
 }
 }
 
 
 ::-webkit-scrollbar-thumb {
 ::-webkit-scrollbar-thumb {
   border-radius: 10px;
   border-radius: 10px;
   background-color: #bdbdbd;
   background-color: #bdbdbd;
-  -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
+  -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, .3);
 }
 }
 
 
 html,
 html,

+ 100 - 13
src/views/page/Update.vue

@@ -6,13 +6,15 @@
         <!-- 组件库 -->
         <!-- 组件库 -->
         <Components @handleClickItem="onAddItem" />
         <Components @handleClickItem="onAddItem" />
         <!--手机容器-->
         <!--手机容器-->
-        <Phone
-          v-if="!isLoading"
-          :data="data"
-          :selectedIndex="selectedIndex"
-          @onEditer="onEditer"
-          @onDeleleItem="onDeleleItem"
-        />
+        <div class="preview-wrap">
+          <Phone
+            v-if="!isLoading"
+            :data="data"
+            :selectedIndex="selectedIndex"
+            @onEditer="onEditer"
+            @onActionItem="onActionItem"
+          />
+        </div>
         <!-- 编辑器 -->
         <!-- 编辑器 -->
         <Editor
         <Editor
           v-if="!isLoading"
           v-if="!isLoading"
@@ -41,6 +43,22 @@ import * as Api from '@/api/page'
 import { SelectImage } from '@/components'
 import { SelectImage } from '@/components'
 import { Components, Phone, Editor } from './modules'
 import { Components, Phone, Editor } from './modules'
 
 
+// 页面类型
+const pageTypes = {
+  '/page/create': {
+    name: 'create',
+    apiMothod: Api.add
+  },
+  '/page/update': {
+    name: 'update',
+    apiMothod: Api.edit
+  },
+  '/page/copy': {
+    name: 'copy',
+    apiMothod: Api.add
+  }
+}
+
 export default {
 export default {
   components: {
   components: {
     SelectImage,
     SelectImage,
@@ -51,6 +69,8 @@ export default {
   },
   },
   data () {
   data () {
     return {
     return {
+      // 页面类型
+      pageType: pageTypes[this.$route.path],
       // loading状态
       // loading状态
       isLoading: false,
       isLoading: false,
       // 页面装修默认数据
       // 页面装修默认数据
@@ -81,10 +101,20 @@ export default {
         // 获取默认数据
         // 获取默认数据
         this.getDefaultData(),
         this.getDefaultData(),
         // 获取当前页面数据
         // 获取当前页面数据
-        this.getPageData()
-      ]).then(() => {
-        this.isLoading = false
-      })
+        this.pageType.name != 'create' && this.getPageData()
+      ])
+        .then(() => {
+          // 生成默认的data
+          this.pageType.name == 'create' && this.createNewData()
+          this.isLoading = false
+        })
+    },
+
+    // 生成默认的data
+    createNewData () {
+      const { defaultData, data } = this
+      data.page = defaultData.page
+      data.items = []
     },
     },
 
 
     // 获取默认数据
     // 获取默认数据
@@ -158,6 +188,61 @@ export default {
         : data.items[index]
         : data.items[index]
     },
     },
 
 
+    // 操作工具栏事件
+    onActionItem (type, index) {
+      const methods = { 'up': 'onUpItem', 'down': 'onDownItem', 'copy': 'onCopyItem', 'delete': 'onDeleleItem' }
+      typeof this[methods[type]] === 'function' && this[methods[type]](index)
+    },
+
+    /**
+     * 上移diy元素
+     * @param index
+     */
+    onUpItem (index) {
+      const { data: { items } } = this
+      const newIndex = index - 1
+      // 判断已经最顶
+      if (index == 0) {
+        return
+      }
+      const item = items.splice(index, 1)[0]
+      items.splice(newIndex, 0, item)
+      if (this.selectedIndex == index) {
+        this.selectedIndex = newIndex
+      }
+    },
+
+    /**
+     * 下移diy元素
+     * @param index
+     */
+    onDownItem (index) {
+      const { data: { items } } = this
+      const newIndex = index + 1
+      // 判断已经最底
+      if (items.length <= newIndex) {
+        return
+      }
+      const item = items.splice(index, 1)[0]
+      items.splice(newIndex, 0, item)
+      if (this.selectedIndex == index) {
+        this.selectedIndex = newIndex
+      }
+    },
+
+    /**
+     * 复制diy元素
+     * @param index
+     */
+    onCopyItem (index) {
+      const { data: { items } } = this
+      if (!this.onCheckAddItem(items[index].type)) {
+        return false
+      }
+      const newItem = _.cloneDeep(items[index])
+      items.splice(index, 0, newItem)
+    },
+
     /**
     /**
      * 删除diy元素
      * 删除diy元素
      * @param index
      * @param index
@@ -181,11 +266,13 @@ export default {
     // 提交到后端api
     // 提交到后端api
     onFormSubmit () {
     onFormSubmit () {
       this.isLoading = true
       this.isLoading = true
-      const { pageId, data, $message } = this
-      Api.edit({ pageId, form: data })
+      const { pageId, data, $message, pageType } = this
+      pageType.apiMothod({ pageId, form: data })
         .then(result => {
         .then(result => {
           // 显示成功
           // 显示成功
           $message.success(result.message, 1.5)
           $message.success(result.message, 1.5)
+          // 跳转到列表页
+          setTimeout(() => this.$router.push('./index'), 1500)
         })
         })
         .finally(() => this.isLoading = false)
         .finally(() => this.isLoading = false)
     }
     }

+ 7 - 0
src/views/page/modules/components/Components.vue

@@ -152,10 +152,17 @@ export default {
 }
 }
 </script>
 </script>
 <style lang="less" scoped>
 <style lang="less" scoped>
+::-webkit-scrollbar {
+  width: 0;
+  height: 0;
+}
+
 // 组件库
 // 组件库
 .components {
 .components {
   width: 310px;
   width: 310px;
   background: #f8f9fa;
   background: #f8f9fa;
+  height: 100%;
+  overflow-y: auto;
 
 
   /deep/.ant-collapse-header {
   /deep/.ant-collapse-header {
     padding: 14px 16px;
     padding: 14px 16px;

+ 8 - 3
src/views/page/modules/editor/style.less

@@ -1,12 +1,17 @@
 @import "~ant-design-vue/es/style/themes/default.less";
 @import "~ant-design-vue/es/style/themes/default.less";
 
 
+::-webkit-scrollbar {
+  width: 0;
+  height: 0;
+}
+
 // 编辑器
 // 编辑器
 .editor {
 .editor {
   min-width: 370px;
   min-width: 370px;
-  min-height: 648px;
-  padding: 10px 15px;
+  padding: 10px 15px 20px 15px;
   background: #f8f9fa;
   background: #f8f9fa;
-  // overflow: hidden;
+  height: 100%;
+  overflow-y: auto;
 
 
   // 标题
   // 标题
   &-title {
   &-title {

+ 55 - 10
src/views/page/modules/phone/Phone.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <div class="phone-content">
+  <div ref="phone-content" class="phone-content">
     <!-- 顶部导航栏 -->
     <!-- 顶部导航栏 -->
     <div
     <div
       class="phone-top optional"
       class="phone-top optional"
@@ -461,9 +461,22 @@
             </p>
             </p>
           </div>
           </div>
 
 
-          <!-- 删除操作 -->
-          <div class="btn-edit-del">
-            <div class="btn-del" @click="handleDeleleItem(index)">删除</div>
+          <!-- 操作工具栏 -->
+          <div class="action-tools">
+            <div class="tools-content">
+              <div class="tools-item" v-for="(itm, idx) in actionTools(item, index)" :key="idx">
+                <a-tooltip placement="right" :getPopupContainer="() => $refs['phone-content']">
+                  <span class="tooltip-text" slot="title">{{ itm.title }}</span>
+                  <div
+                    class="item-btn"
+                    :class="{ disabled: itm.disabled }"
+                    @click.stop="handleActionToolItem(itm, index)"
+                  >
+                    <a-icon class="tools-icon" :type="itm.type" />
+                  </div>
+                </a-tooltip>
+              </div>
+            </div>
           </div>
           </div>
         </div>
         </div>
       </draggable>
       </draggable>
@@ -498,6 +511,9 @@ export default {
       // 禁止拖拽的组件
       // 禁止拖拽的组件
       undragList
       undragList
     }
     }
+  },
+  computed: {
+
   },
   },
   beforeCreate () {
   beforeCreate () {
     this.Icon = Icon
     this.Icon = Icon
@@ -506,6 +522,38 @@ export default {
   },
   },
   methods: {
   methods: {
 
 
+    /**
+     * 操作工具栏
+     * @param item
+     * @param index
+     */
+    actionTools (item, index) {
+      const { data: { items } } = this
+      const isUndrag = inArray(item.type, undragList)
+      return [
+        {
+          title: '上移',
+          type: 'up',
+          disabled: isUndrag || index == 0 || inArray(items[index - 1].type, undragList)
+        },
+        {
+          title: '下移',
+          type: 'down',
+          disabled: isUndrag || items.length <= index + 1 || inArray(items[index + 1].type, undragList)
+        },
+        {
+          title: '复制',
+          type: 'copy',
+          disabled: false
+        },
+        {
+          title: '删除',
+          type: 'delete',
+          disabled: false
+        }
+      ]
+    },
+
     /**
     /**
      * 拖动diy元素更新当前索引
      * 拖动diy元素更新当前索引
      * @param e
      * @param e
@@ -522,12 +570,9 @@ export default {
       this.$emit('onEditer', index)
       this.$emit('onEditer', index)
     },
     },
 
 
-    /**
-     * 删除当前选中的Diy元素
-     * @param index
-     */
-    handleDeleleItem (index) {
-      this.$emit('onDeleleItem', index)
+    // 操作工具栏点击事件
+    handleActionToolItem (acItem, index) {
+      !acItem.disabled && this.$emit('onActionItem', acItem.type, index)
     },
     },
 
 
     // 渲染组件外层容器的样式
     // 渲染组件外层容器的样式

+ 56 - 36
src/views/page/modules/phone/style.less

@@ -13,29 +13,37 @@ dl {
   box-shadow: 0 0 28px 0 #ccc;
   box-shadow: 0 0 28px 0 #ccc;
   border: 1px solid #ddd;
   border: 1px solid #ddd;
   background: #fff;
   background: #fff;
+  position: relative;
+  margin: 0 auto;
 
 
   .phone-top {
   .phone-top {
     width: 100%;
     width: 100%;
-    height: 66px;
+    height: 88px;
     text-align: center;
     text-align: center;
     background-position: center;
     background-position: center;
     background-size: contain;
     background-size: contain;
     background-repeat: no-repeat;
     background-repeat: no-repeat;
 
 
     &.black {
     &.black {
-      background-image: url('~@/assets/img/phone-top-black.png');
+      background-image: url('~@/assets/img/topNavBlack_new.png');
     }
     }
 
 
     &.white {
     &.white {
-      background-image: url('~@/assets/img/phone-top-white.png');
+      background-image: url('~@/assets/img/topNavWhite_new.png');
     }
     }
 
 
     .title {
     .title {
-      margin: 0;
       font-size: 14px;
       font-size: 14px;
       font-weight: normal;
       font-weight: normal;
       white-space: nowrap;
       white-space: nowrap;
-      line-height: 88px;
+      position: absolute;
+      bottom: 0;
+
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      width: 100%;
+      height: 44px;
     }
     }
   }
   }
 
 
@@ -47,45 +55,20 @@ dl {
     line-height: normal;
     line-height: normal;
 
 
     .content {
     .content {
-      overflow-y: auto;
-      height: 640px;
+      // overflow-y: auto;
+      min-height: 640px;
     }
     }
 
 
     .devise-item {
     .devise-item {
       display: block;
       display: block;
-      overflow: hidden;
+      // overflow: hidden;
       font-size: 13px;
       font-size: 13px;
 
 
-      .btn-edit-del {
-        height: 16px;
-        position: absolute;
-        right: 2px;
-        bottom: 2px;
-        display: none;
-        z-index: 90;
-
-        &>div {
-          width: 32px;
-          height: 16px;
-          line-height: 16px;
-          display: inline-block;
-          text-align: center;
-          font-size: 10px;
-          color: #fff;
-          background: rgba(0, 0, 0, 0.4);
-          margin-left: 2px;
-          cursor: pointer;
-          position: relative;
-          z-index: 11;
-        }
-      }
-
       // 选中状态
       // 选中状态
-      &.selected,
-      &:hover {
+      &.selected {
 
 
-        // 显示删除按钮
-        .btn-edit-del {
+        // 显示操作工具栏
+        .action-tools {
           display: block;
           display: block;
         }
         }
       }
       }
@@ -927,4 +910,41 @@ dl {
       cursor: move;
       cursor: move;
     }
     }
   }
   }
+
+  .tooltip-text {
+    white-space: nowrap;
+  }
+
+  // 操作区 (工具栏)
+  .action-tools {
+    display: none;
+    position: absolute;
+    top: 0;
+    right: -48px;
+    z-index: 1;
+    padding-left: 14px;
+
+    .tools-content {
+      border-radius: 4px;
+      line-height: 22px;
+      text-align: left;
+      padding: 4px 10px;
+      background-color: #fff;
+      box-shadow: 0 0 10px 0px rgba(0, 0, 0, 0.1);
+      font-size: 14px;
+      word-break: break-all;
+    }
+
+    .item-btn {
+      cursor: pointer;
+      padding: 3px 0;
+      font-size: 13px;
+
+      &.disabled {
+        color: #dfe2e6;
+      }
+    }
+
+  }
+
 }
 }

+ 11 - 0
src/views/page/style.less

@@ -6,11 +6,22 @@
 
 
 // 页面设计工作区
 // 页面设计工作区
 .work-content {
 .work-content {
+  min-width: 1300px;
+  height: calc(100vh - 156px); // 80px + 60px + 16px
   display: flex;
   display: flex;
   align-items: flex-start;
   align-items: flex-start;
   justify-content: space-between;
   justify-content: space-between;
 }
 }
 
 
+// 手机预览
+.preview-wrap {
+  flex: 1;
+  height: 100%;
+  overflow-y: auto;
+  margin: 0 10px;
+  padding-bottom: 60px;
+}
+
 // 底部操作栏
 // 底部操作栏
 .footer {
 .footer {
   position: fixed;
   position: fixed;