|
|
@@ -0,0 +1,401 @@
|
|
|
+<script lang="ts">
|
|
|
+import Vue from 'vue'
|
|
|
+import draggable from 'vuedraggable'
|
|
|
+export default Vue.extend({
|
|
|
+ name: 'Edit',
|
|
|
+ components: {
|
|
|
+ draggable
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ compList: [
|
|
|
+ {
|
|
|
+ type: 'tips',
|
|
|
+ value: '将我拖拽至右边试试吧',
|
|
|
+ width: 2
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'input',
|
|
|
+ label: '请在下方输入内容',
|
|
|
+ value: '',
|
|
|
+ width: 2,
|
|
|
+ placeholder: '请输入'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'select',
|
|
|
+ label: '请在下方选择内容',
|
|
|
+ value: '',
|
|
|
+ width: 1,
|
|
|
+ options: [
|
|
|
+ { label: '东坡肉', value: '1' },
|
|
|
+ { label: '酱肘子', value: '2' },
|
|
|
+ { label: '白切鸡', value: '3' }
|
|
|
+ ],
|
|
|
+ placeholder: '请选择'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'checkbox',
|
|
|
+ label: '请选择一至多项内容',
|
|
|
+ value: '',
|
|
|
+ width: 1,
|
|
|
+ options: [
|
|
|
+ { label: '东坡肉', value: '1' },
|
|
|
+ { label: '酱肘子', value: '2' },
|
|
|
+ { label: '白切鸡', value: '3' }
|
|
|
+ ],
|
|
|
+ placeholder: '请选择'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'radio',
|
|
|
+ label: '请选择一项内容',
|
|
|
+ value: '',
|
|
|
+ width: 1,
|
|
|
+ options: [
|
|
|
+ { label: '东坡肉', value: '1' },
|
|
|
+ { label: '酱肘子', value: '2' },
|
|
|
+ { label: '白切鸡', value: '3' }
|
|
|
+ ],
|
|
|
+ placeholder: '请选择'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'number',
|
|
|
+ label: '请在下方输入数字',
|
|
|
+ max: 10,
|
|
|
+ min: 0,
|
|
|
+ step: 1,
|
|
|
+ value: 0,
|
|
|
+ width: 1
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'slider',
|
|
|
+ label: '请在下方滑动',
|
|
|
+ max: 10,
|
|
|
+ min: 0,
|
|
|
+ step: 1,
|
|
|
+ value: 0,
|
|
|
+ width: 1
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'textarea',
|
|
|
+ label: '请在下方输入内容',
|
|
|
+ value: '',
|
|
|
+ maxRows: 4,
|
|
|
+ minRows: 2,
|
|
|
+ width: 2,
|
|
|
+ placeholder: '请输入'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'time',
|
|
|
+ label: '请在下方选择时间',
|
|
|
+ value: '',
|
|
|
+ width: 2,
|
|
|
+ placeholder: '请选择时间'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'date',
|
|
|
+ label: '请在下方选择日期',
|
|
|
+ value: '',
|
|
|
+ width: 2,
|
|
|
+ placeholder: '请选择日期'
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ formData: [],
|
|
|
+ isDrag: false,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ cloneItem(item) {
|
|
|
+ let newItem = JSON.parse(JSON.stringify(item))
|
|
|
+ newItem.key = newItem.type + new Date().getTime()
|
|
|
+ return newItem
|
|
|
+ },
|
|
|
+ hover(element) {
|
|
|
+ if(this.isDrag) return
|
|
|
+ let index = this.getIndexByKey(element.key)
|
|
|
+ this.$set(this.formData[index],'hover',true)
|
|
|
+ },
|
|
|
+ blur(element) {
|
|
|
+ let index = this.getIndexByKey(element.key)
|
|
|
+ this.$set(this.formData[index],'hover',false)
|
|
|
+ },
|
|
|
+ getIndexByKey(key) {
|
|
|
+ return this.formData.indexOf(this.formData.find(item => item.key === key))
|
|
|
+ },
|
|
|
+ handleStart(){
|
|
|
+ this.isDrag = true
|
|
|
+ this.formData.forEach(item => {
|
|
|
+ item.hover = false
|
|
|
+ })
|
|
|
+ },
|
|
|
+ handleEnd(){
|
|
|
+ this.isDrag = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="main-box">
|
|
|
+ <div class="comp-lib">
|
|
|
+ <div class="title">
|
|
|
+ 组件库
|
|
|
+ </div>
|
|
|
+ <div class="list">
|
|
|
+ <draggable v-model="compList" :options="{sort:false}" :group="{name:'form',put:false,pull:'clone'}" :clone="cloneItem" class="drag-list">
|
|
|
+ <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>
|
|
|
+ <div v-if="element.type==='input'" :class="[element.type,'form-item']">
|
|
|
+ <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']">
|
|
|
+ <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']">
|
|
|
+ <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']">
|
|
|
+ <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']">
|
|
|
+ <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']">
|
|
|
+ <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']">
|
|
|
+ <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']">
|
|
|
+ <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']">
|
|
|
+ <div class="tips">{{ element.label }}</div>
|
|
|
+ <el-date-picker :value="element.value" :placeholder="element.placeholder" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </transition-group>
|
|
|
+ </draggable>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <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>
|
|
|
+ <draggable v-model="formData" :group="{name:'form'}" @start="handleStart" @end="handleEnd" :options="{sort:true,animation:300}" class="form-body">
|
|
|
+ <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>
|
|
|
+ <div v-if="element.type==='input'" :class="[element.type,'form-item','view',element.hover?'active':'']">
|
|
|
+ <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 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 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 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 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 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 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 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 class="tips">{{ element.label }}</div>
|
|
|
+ <el-date-picker :value="element.value" :placeholder="element.placeholder" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </transition-group>
|
|
|
+ </draggable>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="comp-edit">
|
|
|
+ <div class="title">表单设定</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+ .main-box{
|
|
|
+ overflow: hidden;
|
|
|
+ padding: 0 !important;
|
|
|
+ height: 100%;
|
|
|
+ width: 100%;
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 360px 1fr 360px;
|
|
|
+ grid-template-rows: 1fr;
|
|
|
+ .form-item{
|
|
|
+ cursor: grab;
|
|
|
+ background: white;
|
|
|
+ margin-bottom: -1px;
|
|
|
+ border-top: 1px solid lightgrey;
|
|
|
+ border-bottom: 1px solid lightgrey;
|
|
|
+ padding: 24px;
|
|
|
+ .tips{
|
|
|
+ font-size: 15px;
|
|
|
+ color: #989898;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ }
|
|
|
+ &.select{
|
|
|
+ .el-select{
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.number{
|
|
|
+ .el-input-number{
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.time{
|
|
|
+ .el-date-editor{
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.date{
|
|
|
+ .el-date-editor{
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.view{
|
|
|
+ transition-duration: 300ms;
|
|
|
+ border-radius: 8px;
|
|
|
+ border: 3px solid #2563EB00;
|
|
|
+ padding: 12px 12px;
|
|
|
+ margin-bottom: 0;
|
|
|
+ &.tips{
|
|
|
+ padding: 12px 12px;
|
|
|
+ }
|
|
|
+ &.active{
|
|
|
+ border: 3px solid #2563EB;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .comp-lib{
|
|
|
+ z-index: 1;
|
|
|
+ position: relative;
|
|
|
+ display: grid;
|
|
|
+ grid-template-rows: auto 1fr;
|
|
|
+ box-shadow: 0 1px 4px 0 #00000022;
|
|
|
+ .title{
|
|
|
+ padding: 24px;
|
|
|
+ }
|
|
|
+ .list{
|
|
|
+ position: relative;
|
|
|
+ .drag-list{
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ height: 100%;
|
|
|
+ width: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ overflow-y: auto;
|
|
|
+ .drag-cont{
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .form-view{
|
|
|
+ position: relative;
|
|
|
+ background: #F9FAFB;
|
|
|
+ .scroll-view{
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 0;
|
|
|
+ height: 100%;
|
|
|
+ width: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ overflow-y: scroll;
|
|
|
+ .form-cont{
|
|
|
+ padding: 12px;
|
|
|
+ border-radius: 16px;
|
|
|
+ margin: 24px;
|
|
|
+ background: white;
|
|
|
+ width: calc(100% - 48px);
|
|
|
+ box-shadow: 0 1px 4px 0 #00000022;
|
|
|
+ .form-head{
|
|
|
+ padding: 12px;
|
|
|
+ border-radius: 8px;
|
|
|
+ transition-duration: 300ms;
|
|
|
+ border: 3px solid #2563EB00;
|
|
|
+ &:hover{
|
|
|
+ border: 3px solid #2563EB;
|
|
|
+ }
|
|
|
+ .title{
|
|
|
+ font-size: 36px;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+ .tips{
|
|
|
+ font-size: 20px;
|
|
|
+ color: #989898;
|
|
|
+ margin-bottom: 6px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .form-body{
|
|
|
+ .drag-cont{
|
|
|
+ display: block;
|
|
|
+ width: 100%;
|
|
|
+ min-height: 300px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .comp-edit{
|
|
|
+ z-index: 1;
|
|
|
+ position: relative;
|
|
|
+ box-shadow: 0 1px 4px 0 #00000022;
|
|
|
+ .title{
|
|
|
+ padding: 24px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|