zhoujump 3 mesiacov pred
rodič
commit
8ddddb8970

BIN
public/static/guide/组件宽度.mp4


+ 0 - 6
src/layout/index.vue

@@ -69,11 +69,6 @@ export default {
   mounted() {
     this.refreshRoute()
     this.initGuards()
-    window.addEventListener('resize', () => {
-      this.collapse.maxWidth = 0
-      this.collapse.minWidth = 0
-      this.changeCollapse()
-    })
   },
   methods: {
     changeCollapse() {
@@ -102,7 +97,6 @@ export default {
       this.menuRouter = this.$router.options.routes[0].children
       this.breadcrumb = this.$route.matched
       this.menuRouter.forEach((item, index) => {
-        console.log(this.$route.name)
         if (item.name === this.$route.name) {
           this.menuActive = index
           if (item.meta.collapse !== undefined) {

+ 68 - 0
src/views/guide/index.vue

@@ -0,0 +1,68 @@
+<script lang="ts">
+import Vue from 'vue'
+
+export default Vue.extend({
+  name: "index",
+  props: {
+    video: {
+      type: String,
+      default: ''
+    },
+    text: {
+      type: String,
+      default: ''
+    },
+    title: {
+      type: String,
+      default: ''
+    }
+  },
+})
+</script>
+
+<template>
+  <el-popover
+    popper-class="popover"
+    placement="left"
+    width="400"
+    trigger="hover">
+    <div class="guide-cont">
+      <video class="guide-video" autoplay loop :src="video" muted></video>
+      <div class="title">{{title}}</div>
+      <div class="text">{{text}}</div>
+    </div>
+    <div class="guide" slot="reference">?</div>
+  </el-popover>
+</template>
+
+<style scoped>
+  .guide{
+    color: gray;
+    cursor: help;
+    border-radius: 50%;
+    display: inline-block;
+    font-weight: bold;
+    font-size: 13px;
+    width: 16px;
+    line-height: 14px;
+    text-align: center;
+    border: 1px solid gray;
+    height: 16px;
+  }
+  .guide-cont{
+    width: 100%;
+    .title{
+      color: #353535;
+      font-size: 22px;
+      font-weight: bold;
+    }
+    .text{
+      margin-top: 8px;
+    }
+    .guide-video{
+      mix-blend-mode: darken;
+      width: 100%;
+      aspect-ratio: 2/1;
+    }
+  }
+</style>

+ 216 - 34
src/views/preRegManage/edit.vue

@@ -1,17 +1,19 @@
 <script lang="ts">
 import Vue from 'vue'
+import guide from '@/views/guide/index'
 import draggable from 'vuedraggable'
 export default Vue.extend({
   name: 'Edit',
   components: {
-    draggable
+    draggable,
+    guide
   },
   data() {
     return {
       compList: [
         {
           type: 'tips',
-          value: '将我拖拽至右边试试吧',
+          label: '将我拖拽至右边试试吧',
           width: 2
         },
         {
@@ -42,8 +44,7 @@ export default Vue.extend({
             { label: '东坡肉', value: '1' },
             { label: '酱肘子', value: '2' },
             { label: '白切鸡', value: '3' }
-          ],
-          placeholder: '请选择'
+          ]
         },
         {
           type: 'radio',
@@ -54,8 +55,7 @@ export default Vue.extend({
             { label: '东坡肉', value: '1' },
             { label: '酱肘子', value: '2' },
             { label: '白切鸡', value: '3' }
-          ],
-          placeholder: '请选择'
+          ]
         },
         {
           type: 'number',
@@ -100,34 +100,48 @@ export default Vue.extend({
         }
       ],
       formData: [],
+      trashData: [],
+      formInfo: {
+        name: '未命名表单',
+        desc: '从右侧拖动组件到表单区域'
+      },
       isDrag: false,
+      currentKey: '',
+      currentData: {},
+      hoverKey: ''
     }
   },
   methods: {
+    choseComp(element) {
+      this.currentKey = element.key
+      this.currentData = element
+    },
     cloneItem(item) {
-      let newItem = JSON.parse(JSON.stringify(item))
+      const newItem = JSON.parse(JSON.stringify(item))
       newItem.key = newItem.type + new Date().getTime()
       return newItem
     },
-    hover(element) {
-      if(this.isDrag) return
+    removeTrash(element){
       let index = this.getIndexByKey(element.key)
-      this.$set(this.formData[index],'hover',true)
+      this.trashData.splice(index,1)
+    },
+    hover(element) {
+      if (this.isDrag) return
+      this.hoverKey = element.key
     },
     blur(element) {
-      let index = this.getIndexByKey(element.key)
-      this.$set(this.formData[index],'hover',false)
+      this.hoverKey = ''
     },
     getIndexByKey(key) {
       return this.formData.indexOf(this.formData.find(item => item.key === key))
     },
-    handleStart(){
+    handleStart() {
       this.isDrag = true
       this.formData.forEach(item => {
         item.hover = false
       })
     },
-    handleEnd(){
+    handleEnd() {
       this.isDrag = false
     }
   }
@@ -145,7 +159,7 @@ export default Vue.extend({
           <transition-group class="drag-cont">
             <div v-for="(element) in compList" :key="element.type">
               <div v-if="element.type==='tips'" :class="[element.type,'form-item']">
-                <div class="tips">{{ element.value }}</div>
+                <div class="tips">{{ element.label }}</div>
               </div>
               <div v-if="element.type==='input'" :class="[element.type,'form-item']">
                 <div class="tips">{{ element.label }}</div>
@@ -197,55 +211,55 @@ export default Vue.extend({
     <div class="form-view">
       <div class="scroll-view">
         <div class="form-cont">
-          <div class="form-head">
-            <div class="title">未命名表单</div>
-            <div class="tips">从右侧拖动组件到表单区域</div>
+          <div :class="['form-head',getIndexByKey(currentKey) === -1?'active':'']" @click="currentKey=''">
+            <div class="title">{{ formInfo.name }}</div>
+            <div class="tips">{{ formInfo.desc }}</div>
           </div>
-          <draggable v-model="formData" :group="{name:'form'}" @start="handleStart" @end="handleEnd" :options="{sort:true,animation:300}" class="form-body">
+          <draggable v-model="formData" :group="{name:'form'}" :options="{sort:true,animation:300}" class="form-body" @start="handleStart" @end="handleEnd">
             <transition-group class="drag-cont">
-              <div v-for="element in formData" :key="element.key" @mouseenter="hover(element)" @mouseleave="blur(element)">
-                <div v-if="element.type==='tips'" :class="[element.type,'form-item','view',{'active':element.hover}]">
-                  <div class="tips">{{ element.value }}</div>
+              <div v-for="element in formData" :key="element.key" :style="{gridColumn:'span '+element.width}" @click="choseComp(element)" @mouseenter="hover(element)" @mouseleave="blur(element)">
+                <div v-if="element.type==='tips'" :class="[element.type,'form-item','view',{'active':element.key===hoverKey||element.key===currentKey}]">
+                  <div class="tips">{{ element.label }}</div>
                 </div>
-                <div v-if="element.type==='input'" :class="[element.type,'form-item','view',element.hover?'active':'']">
+                <div v-if="element.type==='input'" :class="[element.type,'form-item','view',{'active':element.key===hoverKey||element.key===currentKey}]">
                   <div class="tips">{{ element.label }}</div>
                   <el-input :value="element.value" :placeholder="element.placeholder" />
                 </div>
-                <div v-if="element.type==='select'" :class="[element.type,'form-item','view',{'active':element.hover}]">
+                <div v-if="element.type==='select'" :class="[element.type,'form-item','view',{'active':element.key===hoverKey||element.key===currentKey}]">
                   <div class="tips">{{ element.label }}</div>
                   <el-select :value="element.value" :placeholder="element.placeholder">
                     <el-option v-for="item in element.options" :key="item.value" :label="item.label" :value="item.value" />
                   </el-select>
                 </div>
-                <div v-if="element.type==='checkbox'" :class="[element.type,'form-item','view',{'active':element.hover}]">
+                <div v-if="element.type==='checkbox'" :class="[element.type,'form-item','view',{'active':element.key===hoverKey||element.key===currentKey}]">
                   <div class="tips">{{ element.label }}</div>
                   <el-checkbox-group :value="element.value">
                     <el-checkbox v-for="item in element.options" :key="item.value" :label="item.label" />
                   </el-checkbox-group>
                 </div>
-                <div v-if="element.type==='radio'" :class="[element.type,'form-item','view',{'active':element.hover}]">
+                <div v-if="element.type==='radio'" :class="[element.type,'form-item','view',{'active':element.key===hoverKey||element.key===currentKey}]">
                   <div class="tips">{{ element.label }}</div>
                   <el-radio-group :value="element.value">
                     <el-radio v-for="item in element.options" :key="item.value" :label="item.label" />
                   </el-radio-group>
                 </div>
-                <div v-if="element.type==='number'" :class="[element.type,'form-item','view',{'active':element.hover}]">
+                <div v-if="element.type==='number'" :class="[element.type,'form-item','view',{'active':element.key===hoverKey||element.key===currentKey}]">
                   <div class="tips">{{ element.label }}</div>
                   <el-input-number :value="element.value" :max="element.max" :min="element.min" :step="element.step" prefix-icon="el-icon-user" :placeholder="element.placeholder" />
                 </div>
-                <div v-if="element.type==='slider'" :class="[element.type,'form-item','view',{'active':element.hover||element.active}]">
+                <div v-if="element.type==='slider'" :class="[element.type,'form-item','view',{'active':element.key===hoverKey||element.key===currentKey}]">
                   <div class="tips">{{ element.label }}</div>
                   <el-slider :value="element.value" :max="element.max" :min="element.min" :step="element.step" prefix-icon="el-icon-user" :placeholder="element.placeholder" />
                 </div>
-                <div v-if="element.type==='textarea'" :class="[element.type,'form-item','view',{'active':element.hover||element.active}]">
+                <div v-if="element.type==='textarea'" :class="[element.type,'form-item','view',{'active':element.key===hoverKey||element.key===currentKey}]">
                   <div class="tips">{{ element.label }}</div>
                   <el-input :value="element.value" type="textarea" :placeholder="element.placeholder" :autosize="{ minRows: element.minRows, maxRows: element.maxRows}" />
                 </div>
-                <div v-if="element.type==='time'" :class="[element.type,'form-item','view',{'active':element.hover||element.active}]">
+                <div v-if="element.type==='time'" :class="[element.type,'form-item','view',{'active':element.key===hoverKey||element.key===currentKey}]">
                   <div class="tips">{{ element.label }}</div>
                   <el-time-picker :value="element.value" :placeholder="element.placeholder" />
                 </div>
-                <div v-if="element.type==='date'" :class="[element.type,'form-item','view',{'active':element.hover||element.active}]">
+                <div v-if="element.type==='date'" :class="[element.type,'form-item','view',{'active':element.key===hoverKey||element.key===currentKey}]">
                   <div class="tips">{{ element.label }}</div>
                   <el-date-picker :value="element.value" :placeholder="element.placeholder" />
                 </div>
@@ -256,13 +270,71 @@ export default Vue.extend({
       </div>
     </div>
     <div class="comp-edit">
-      <div class="title">表单设定</div>
+      <template v-if="getIndexByKey(currentKey) === -1">
+        <div class="title">表单设定</div>
+        <div class="body">
+          <div class="tips">表单名称</div>
+          <el-input v-model="formInfo.name" placeholder="请输入表单名称" />
+          <div class="tips">表单介绍</div>
+          <el-input type="textarea" v-model="formInfo.desc" placeholder="请输入表单介绍" />
+        </div>
+        <div class="button">
+          <el-button type="primary">保存表单</el-button>
+        </div>
+      </template>
+      <template v-else>
+        <div class="title">
+          <span class="el-icon-arrow-left icon" @click="currentKey=''" />
+          组件设定
+        </div>
+        <div class="body">
+
+          <div class="tips">表单项介绍</div>
+          <el-input v-model="currentData.label" type="textarea" placeholder="请输入表单项介绍"></el-input>
+
+          <template v-if="['input','select','textarea','time','date'].includes(currentData.type)">
+            <div class="tips">提示文字</div>
+            <el-input v-model="currentData.placeholder" placeholder="请输入提示文字"></el-input>
+          </template>
+
+          <div class="tips">
+            组件宽度
+            <guide
+              video="/static/guide/组件宽度.mp4"
+              title="组件宽度"
+              text="设置所选定组件的宽度,使其占据全部宽度或者只占据一半宽度。"
+            ></guide>
+          </div>
+          <el-radio-group size="small" v-model="currentData.width">
+            <el-radio-button :label="1">窄</el-radio-button>
+            <el-radio-button :label="2">宽</el-radio-button>
+          </el-radio-group>
+
+        </div>
+        <div class="button">
+          <el-button type="danger">删除组件</el-button>
+        </div>
+      </template>
+    </div>
+    <div :class="['trash-bin',isDrag?'':'hide']">
+      <div class="trash-inner">
+        <draggable v-model="trashData" :group="{name:'form'}" :options="{sort:false,animation:300}" :class="['trash-cont',trashData.length?'':'hide']">
+          <transition-group class="drag-cont">
+            <div v-for="element in trashData" :key="element.key" class="form-item view">
+              <div class="tips">{{element.label}}</div>
+              <div @click="removeTrash(element)" class="del el-icon-delete"></div>
+            </div>
+          </transition-group>
+        </draggable>
+      </div>
+      <div class="text">回收站</div>
     </div>
   </div>
 </template>
 
 <style scoped>
   .main-box{
+    position: relative;
     overflow: hidden;
     padding: 0 !important;
     height: 100%;
@@ -316,6 +388,75 @@ export default Vue.extend({
         }
       }
     }
+    .trash-bin{
+      box-shadow: -4px 8px 12px 0 #00000044;
+      padding: 8px;
+      position: absolute;
+      border-radius: 32px 32px 0 0;
+      z-index: 3;
+      right: 200px;
+      bottom: 0;
+      width: 360px;
+      height: 150px;
+      background: lightgrey;
+      transition-duration: 300ms;
+      .trash-inner{
+        position: relative;
+        outline: #e4e4e4 5px solid;
+        border-radius: 24px;
+        width: 100%;
+        height: 60px;
+        background-image: linear-gradient( #b3b3b3, #2b2b2b);
+        .trash-cont{
+          overflow: hidden;
+          border-radius: 24px;
+          position: absolute;
+          width: 100%;
+          height: 200%;
+          left: 0;
+          bottom: 0;
+          &.hide{
+            height: 100%;
+          }
+          .drag-cont{
+            padding: 6px 12px 0;
+            overflow: hidden;
+            overflow-y: scroll;
+            display: block;
+            width: calc(100% + 20px);
+            height: 100%;
+            .form-item{
+              position: sticky;
+              left: 0;
+              top: 0;
+              box-shadow: 0 0 6px 0 #00000022;
+              height: 100%;
+              .del{
+                position: absolute;
+                right: 16px;
+                top: 16px;
+                cursor: pointer;
+              }
+            }
+          }
+        }
+      }
+      .text{
+        width: 100%;
+        text-align: center;
+        margin-top: 16px;
+        font-size: 36px;
+        font-weight: bold;
+        color: gray;
+        text-shadow: 4px 4px 4px 4px #ffffff;
+      }
+      &.hide{
+        bottom: -160px;
+      }
+      &:hover{
+        bottom: -60px;
+      }
+    }
     .comp-lib{
       z-index: 1;
       position: relative;
@@ -366,7 +507,7 @@ export default Vue.extend({
             border-radius: 8px;
             transition-duration: 300ms;
             border: 3px solid #2563EB00;
-            &:hover{
+            &:hover,&.active{
               border: 3px solid #2563EB;
             }
             .title{
@@ -381,9 +522,14 @@ export default Vue.extend({
           }
           .form-body{
             .drag-cont{
-              display: block;
+              display: grid;
+              grid-template-columns: 1fr 1fr;
               width: 100%;
               min-height: 300px;
+              align-content: start;
+              .form-item{
+                height: fit-content;
+              }
             }
           }
         }
@@ -393,8 +539,44 @@ export default Vue.extend({
       z-index: 1;
       position: relative;
       box-shadow: 0 1px 4px 0 #00000022;
+      display: grid;
+      grid-template-rows: auto 1fr auto;
+      .body{
+        padding: 0 24px;
+        display: flex;
+        flex-direction: column;
+        align-items: flex-end;
+        .tips{
+          width: 100%;
+          font-size: 16px;
+          color: #505050;
+          margin-bottom: 6px;
+          margin-top: 12px;
+        }
+      }
+      .button{
+        display: flex;
+        justify-content: flex-end;
+        padding: 24px;
+      }
       .title{
         padding: 24px;
+        display: flex;
+        align-items: center;
+        .icon{
+          margin-left: -4px;
+          margin-top: -4px;
+          margin-right: 8px;
+          font-size: 24px;
+          cursor: pointer;
+          padding: 4px;
+          border-radius: 8px;
+          transition-duration: 300ms;
+          &:hover{
+            color: #2563EB;
+            background: #ececec;
+          }
+        }
       }
     }
   }