|
|
@@ -0,0 +1,852 @@
|
|
|
+<script lang="ts">
|
|
|
+import Vue from 'vue'
|
|
|
+import { getMyFields, saveMyFields } from '@/api/form'
|
|
|
+import guide from '@/views/components/guidePopover.vue'
|
|
|
+import draggable from 'vuedraggable'
|
|
|
+import countryCode from '@/lib/countryCode.json'
|
|
|
+import {
|
|
|
+ pcTextArr,
|
|
|
+ pcaTextArr
|
|
|
+} from 'element-china-area-data'
|
|
|
+
|
|
|
+export default Vue.extend({
|
|
|
+ name: 'Edit',
|
|
|
+ components: {
|
|
|
+ draggable,
|
|
|
+ guide
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ compList: [
|
|
|
+
|
|
|
+ ],
|
|
|
+ currentData: {
|
|
|
+ id: '',
|
|
|
+ field_name: '',
|
|
|
+ field_type: 'input',
|
|
|
+ field_label: '请在下方输入名字',
|
|
|
+ field_data: {
|
|
|
+ value: '',
|
|
|
+ width: 6,
|
|
|
+ placeholder: '请输入名字',
|
|
|
+ pattern: '',
|
|
|
+ options: [],
|
|
|
+ max: 10,
|
|
|
+ min: 0,
|
|
|
+ step: 1,
|
|
|
+ rows: [2, 4],
|
|
|
+ rangeSeparator: '至',
|
|
|
+ endPlaceholder: '结束时间'
|
|
|
+ },
|
|
|
+ is_required: 0
|
|
|
+ },
|
|
|
+ selectInput: '',
|
|
|
+ pcTextArr,
|
|
|
+ pcaTextArr,
|
|
|
+ countryCode,
|
|
|
+ copyShow: false,
|
|
|
+ loading: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.init()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ init() {
|
|
|
+ this.getFields()
|
|
|
+ },
|
|
|
+ getFields() {
|
|
|
+ if (this.loading) { return }
|
|
|
+ this.loading = true
|
|
|
+ getMyFields().then(res => {
|
|
|
+ if (this.compList.length === 0 && res.data.length > 0) {
|
|
|
+ this.currentData = res.data[0]
|
|
|
+ }
|
|
|
+ this.compList = res.data
|
|
|
+ this.loading = false
|
|
|
+ }).catch(err => {
|
|
|
+ this.loading = false
|
|
|
+ this.$notify({
|
|
|
+ title: '出错了',
|
|
|
+ message: err.message,
|
|
|
+ type: 'error'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ save() {
|
|
|
+ if (this.loading) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.loading = true
|
|
|
+ saveMyFields(this.currentData.id, this.currentData.field_label, this.currentData.field_type, this.currentData.field_data, this.currentData.is_required).then(res => {
|
|
|
+ this.loading = false
|
|
|
+ this.$notify({
|
|
|
+ title: '保存成功',
|
|
|
+ message: '组件已保存完成',
|
|
|
+ type: 'success'
|
|
|
+ })
|
|
|
+ this.getFields()
|
|
|
+ }).catch(err => {
|
|
|
+ this.loading = false
|
|
|
+ this.$notify({
|
|
|
+ title: '出错了',
|
|
|
+ message: err.message,
|
|
|
+ type: 'error'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ choseComp(element) {
|
|
|
+ this.currentData = element
|
|
|
+ },
|
|
|
+ addSelectItem() {
|
|
|
+ if (this.selectInput.length === 0) { return }
|
|
|
+ this.currentData.field_data.options.push({
|
|
|
+ label: this.selectInput,
|
|
|
+ value: this.selectInput
|
|
|
+ })
|
|
|
+ this.selectInput = ''
|
|
|
+ },
|
|
|
+ removeSelectItem(index) {
|
|
|
+ this.currentData.field_data.options.splice(index, 1)
|
|
|
+ },
|
|
|
+ cloneItem(currentData) {
|
|
|
+ if(this.loading) { return }
|
|
|
+ this.loading = true
|
|
|
+ this.copyShow=false
|
|
|
+ saveMyFields('', currentData.field_label + '(副本)', currentData.field_type, currentData.field_data, currentData.is_required).then(res => {
|
|
|
+ this.$notify({
|
|
|
+ title: '复制成功',
|
|
|
+ message: '组件副本已保存完成',
|
|
|
+ type: 'success'
|
|
|
+ })
|
|
|
+ this.loading = false
|
|
|
+ this.save()
|
|
|
+ }).catch(err => {
|
|
|
+ this.loading = false
|
|
|
+ this.$notify({
|
|
|
+ title: '出错了',
|
|
|
+ message: err.message,
|
|
|
+ type: 'error'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ creatNew() {
|
|
|
+ this.save()
|
|
|
+ this.currentData = {
|
|
|
+ id: '',
|
|
|
+ field_name: '',
|
|
|
+ field_type: 'input',
|
|
|
+ field_label: '请在下方输入名字',
|
|
|
+ field_data: {
|
|
|
+ value: '',
|
|
|
+ width: 6,
|
|
|
+ placeholder: '请输入名字',
|
|
|
+ pattern: '',
|
|
|
+ options: [],
|
|
|
+ max: 10,
|
|
|
+ min: 0,
|
|
|
+ step: 1,
|
|
|
+ rows: [2, 4],
|
|
|
+ rangeSeparator: '至'
|
|
|
+ },
|
|
|
+ is_required: 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div v-loading="loading" class="main-box">
|
|
|
+ <div class="comp-lib">
|
|
|
+ <div class="add el-icon-plus" @click="creatNew" />
|
|
|
+ <div class="title">
|
|
|
+ 自定义组件库
|
|
|
+ </div>
|
|
|
+ <div class="list">
|
|
|
+ <div class="drag-list">
|
|
|
+ <div class="drag-cont">
|
|
|
+ <div v-for="(element) in compList" :key="element.id" @click="choseComp(element)">
|
|
|
+ <div v-if="element.field_type==='tips'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='input'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <el-input v-model="element.field_data.value" :placeholder="element.field_data.placeholder" />
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='email'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <div>
|
|
|
+ <el-input v-model="element.field_data.value" :placeholder="element.field_data.placeholder" />
|
|
|
+ </div>
|
|
|
+ <div class="code-input">
|
|
|
+ <el-input v-model="element.field_data.value" :placeholder="element.field_data.codePlaceholder" />
|
|
|
+ <el-button>获取验证码</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='phone'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <div class="phone-input">
|
|
|
+ <el-select v-model="element.field_data.value" :placeholder="element.field_data.placeholder">
|
|
|
+ <el-option v-for="(item,index) in countryCode" :key="item.country_code+index" :value="item.phone_code" :label="'+'+item.phone_code+'('+item.chinese_name+')'" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='select'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <el-select v-model="element.field_data.value" :placeholder="element.field_data.placeholder">
|
|
|
+ <el-option v-for="item in element.field_data.options" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='checkbox'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <el-checkbox-group v-model="element.field_data.value">
|
|
|
+ <el-checkbox v-for="item in element.field_data.options" :key="item.value" :label="item.label" />
|
|
|
+ </el-checkbox-group>
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='radio'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <el-radio-group v-model="element.field_data.value">
|
|
|
+ <el-radio v-for="item in element.field_data.options" :key="item.value" :label="item.label" />
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='number'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <el-input-number v-model="element.field_data.value" :max="element.field_data.max" :min="element.field_data.min" :step="element.field_data.step" prefix-icon="el-icon-user" :placeholder="element.field_data.placeholder" />
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='slider'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <el-slider v-model="element.field_data.value" :max="element.field_data.max" :min="element.field_data.min" :step="element.field_data.step" prefix-icon="el-icon-user" :placeholder="element.field_data.placeholder" />
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='textarea'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <el-input v-model="element.field_data.value" type="textarea" :placeholder="element.field_data.placeholder" :autosize="{ minRows: element.field_data.rows[0], maxRows: element.field_data.rows[1]}" />
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='region'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <el-cascader
|
|
|
+ :placeholder="element.field_data.placeholder"
|
|
|
+ size="large"
|
|
|
+ :options="element.field_data.range===2?pcTextArr:pcaTextArr"
|
|
|
+ value="element.field_data.value"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='time'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <el-time-picker v-model="element.field_data.value" :placeholder="element.field_data.placeholder" />
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='timeRange'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item','view']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <el-time-picker v-model="element.field_data.value" is-range :start-placeholder="element.field_data.placeholder" :end-placeholder="element.field_data.endPlaceholder" :range-separator="element.field_data.rangeSeparator" />
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='date'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <el-date-picker v-model="element.field_data.value" :placeholder="element.field_data.placeholder" />
|
|
|
+ </div>
|
|
|
+ <div v-if="element.field_type==='dateRange'" :class="[element.field_type,element.id===currentData.id?'active':'','form-item']">
|
|
|
+ <div class="tips">{{ element.field_label }}</div>
|
|
|
+ <el-date-picker v-model="element.field_data.value" type="daterange" :start-placeholder="element.field_data.placeholder" :end-placeholder="element.field_data.endPlaceholder" :range-separator="element.field_data.rangeSeparator" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </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>
|
|
|
+ <div class="form-body">
|
|
|
+ <div class="drag-cont">
|
|
|
+ <div :style="{gridColumn:'span '+currentData.field_data.width}" :class="[currentData.is_required?'required':'']">
|
|
|
+ <div v-if="currentData.field_type==='tips'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='input'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <el-input v-model="currentData.field_data.value" :placeholder="currentData.field_data.placeholder" />
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='email'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <div>
|
|
|
+ <el-input v-model="currentData.field_data.value" :placeholder="currentData.field_data.placeholder" />
|
|
|
+ </div>
|
|
|
+ <div class="code-input">
|
|
|
+ <el-input v-model="currentData.field_data.value" :placeholder="currentData.field_data.codePlaceholder" />
|
|
|
+ <el-button>获取验证码</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='phone'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <div class="phone-input">
|
|
|
+ <el-select v-model="currentData.field_data.country" :placeholder="currentData.field_data.placeholder">
|
|
|
+ <el-option v-for="(item,index) in currentData.field_data.countryCode" :key="item.country_code+index" :label="'+'+item.phone_code+'('+item.chinese_name+')'" :value="item.country_code" />
|
|
|
+ </el-select>
|
|
|
+ <el-input v-model="currentData.field_data.value" :placeholder="currentData.field_data.placeholder" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='select'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <el-select v-model="currentData.field_data.value" :placeholder="currentData.field_data.placeholder">
|
|
|
+ <el-option v-for="item in currentData.field_data.options" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='checkbox'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <el-checkbox-group v-model="currentData.field_data.value">
|
|
|
+ <el-checkbox v-for="item in currentData.field_data.options" :key="item.value" :label="item.value" />
|
|
|
+ </el-checkbox-group>
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='radio'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <el-radio-group v-model="currentData.field_data.value">
|
|
|
+ <el-radio v-for="item in currentData.field_data.options" :key="item.value" :label="item.label" />
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='number'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <el-input-number v-model="currentData.field_data.value" :max="currentData.field_data.max" :min="currentData.field_data.min" :step="currentData.field_data.step" prefix-icon="el-icon-user" :placeholder="currentData.field_data.placeholder" />
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='slider'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <el-slider v-model="currentData.field_data.value" :max="currentData.field_data.max" :min="currentData.field_data.min" :step="currentData.field_data.step" prefix-icon="el-icon-user" :placeholder="currentData.field_data.placeholder" />
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='textarea'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <el-input v-model="currentData.field_data.value" type="textarea" :placeholder="currentData.field_data.placeholder" :autosize="{ minRows: currentData.field_data.rows[0], maxRows: currentData.field_data.rows[1]}" />
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='region'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <el-cascader
|
|
|
+ v-model="currentData.field_data.value"
|
|
|
+ :placeholder="currentData.field_data.placeholder"
|
|
|
+ size="large"
|
|
|
+ :options="currentData.field_data.range===2?pcTextArr:pcaTextArr"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='time'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <el-time-picker :key="currentData.field_type" v-model="currentData.field_data.value" :placeholder="currentData.field_data.placeholder" />
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='timeRange'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <el-time-picker :key="currentData.field_type" v-model="currentData.field_data.value" is-range :start-placeholder="currentData.field_data.placeholder" :end-placeholder="currentData.field_data.endPlaceholder" :range-separator="currentData.field_data.rangeSeparator" />
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='date'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <el-date-picker :key="currentData.field_type" v-model="currentData.field_data.value" :placeholder="currentData.field_data.placeholder" />
|
|
|
+ </div>
|
|
|
+ <div v-if="currentData.field_type==='dateRange'" :class="[currentData.field_type,'form-item','view']">
|
|
|
+ <div class="tips">{{ currentData.field_label }}</div>
|
|
|
+ <el-date-picker :key="currentData.field_type" v-model="currentData.field_data.value" type="daterange" :start-placeholder="currentData.field_data.placeholder" :end-placeholder="currentData.field_data.endPlaceholder" :range-separator="currentData.field_data.rangeSeparator" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="comp-edit">
|
|
|
+ <div class="button">
|
|
|
+ <el-popover
|
|
|
+ v-model="copyShow"
|
|
|
+ placement="bottom"
|
|
|
+ trigger="click"
|
|
|
+ title="确定创建组件副本?"
|
|
|
+ popper-class="copy-popover"
|
|
|
+ >
|
|
|
+ <div class="body">
|
|
|
+ <div class="content">
|
|
|
+ 点击确定将创建一个当前组件的副本。
|
|
|
+ </div>
|
|
|
+ <div class="button-list">
|
|
|
+ <el-button @click="copyShow=false" size="mini">取消</el-button>
|
|
|
+ <el-button @click="cloneItem(currentData)" type="primary" size="mini">确定</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-button slot="reference" type="primary" icon="el-icon-document-copy" circle />
|
|
|
+ </el-popover>
|
|
|
+ <el-button type="primary" @click="save">保存组件</el-button>
|
|
|
+ </div>
|
|
|
+ <div class="body-cont">
|
|
|
+ <div class="body">
|
|
|
+ <div class="tips">
|
|
|
+ 组件类型
|
|
|
+ </div>
|
|
|
+ <el-select v-model="currentData.field_type" class="pattern-select" placeholder="选择组件类型">
|
|
|
+ <el-option label="单行输入框组件" value="input" />
|
|
|
+ <el-option label="多行输入框组件" value="textarea" />
|
|
|
+ <el-option label="下拉选择组件" value="select" />
|
|
|
+ <el-option label="多项选择组件" value="checkbox" />
|
|
|
+ <el-option label="单项选择组件" value="radio" />
|
|
|
+ <el-option label="数字输入组件" value="number" />
|
|
|
+ <el-option label="数字滑块组件" value="slider" />
|
|
|
+ <el-option label="时间选择组件" value="time" />
|
|
|
+ <el-option label="时间范围选择组件" value="timeRange" />
|
|
|
+ <el-option label="日期选择组件" value="date" />
|
|
|
+ <el-option label="日期范围选择组件" value="dateRange" />
|
|
|
+ </el-select>
|
|
|
+
|
|
|
+ <div class="tips">
|
|
|
+ 表单项介绍
|
|
|
+ <guide
|
|
|
+ video="/static/guide/表单项介绍.jpg"
|
|
|
+ title="表单项介绍"
|
|
|
+ text="展示在输入框上方的大段文本,用于介绍和提示该处应输入的内容。"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <el-input v-model="currentData.field_label" type="textarea" placeholder="请输入表单项介绍" />
|
|
|
+
|
|
|
+ <template>
|
|
|
+ <div class="tips">是否必填</div>
|
|
|
+ <el-switch :active-value="1" :inactive-value="0" v-model="currentData.is_required" />
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="['input','select','textarea','time','date','region','email','phone'].includes(currentData.field_type)">
|
|
|
+ <div class="tips">
|
|
|
+ 提示文字
|
|
|
+ <guide
|
|
|
+ video="/static/guide/提示文字.jpg"
|
|
|
+ title="提示文字"
|
|
|
+ text="用户输入内容前,展示在输入框中的简短文本,用于提示该处应输入的内容。"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <el-input v-model="currentData.field_data.placeholder" placeholder="请输入提示文字" />
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="['textarea'].includes(currentData.field_type)">
|
|
|
+ <div class="tips">
|
|
|
+ 行数范围
|
|
|
+ </div>
|
|
|
+ <el-slider v-model="currentData.field_data.rows" class="slider" range :max="12" :min="1" />
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="['input','textarea'].includes(currentData.field_type)">
|
|
|
+ <div class="tips">验证规则</div>
|
|
|
+ <el-input v-model="currentData.field_data.pattern" :rows="3" type="textarea" placeholder="规则正则表达式" />
|
|
|
+ <el-select v-model="currentData.field_data.pattern" class="pattern-select" placeholder="选择预设规则">
|
|
|
+ <el-option label="不做判断" value="" />
|
|
|
+ <el-option label="国内手机号" value="^1\d{10}$" />
|
|
|
+ <el-option label="国内身份证号码" value="^[1-9]\d{5}(19\d{2}|20\d{2})((0[1-9])|(1[0-2]))((0[1-9])|([1-2]\d)|(3[0-1]))\d{3}(\d|X|x)$" />
|
|
|
+ <el-option label="电子邮箱" value="^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$" />
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="currentData.field_type==='region'">
|
|
|
+ <div class="tips">
|
|
|
+ 地区范围
|
|
|
+ </div>
|
|
|
+ <el-radio-group v-model="currentData.field_data.range" size="small">
|
|
|
+ <el-radio-button :label="2">省/市</el-radio-button>
|
|
|
+ <el-radio-button :label="3">省/市/县</el-radio-button>
|
|
|
+ </el-radio-group>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="['timeRange','dateRange'].includes(currentData.field_type)">
|
|
|
+ <div class="tips">
|
|
|
+ 起始提示文字
|
|
|
+ <guide
|
|
|
+ video="/static/guide/起始提示文字.jpg"
|
|
|
+ title="起始提示文字"
|
|
|
+ text="时间与日期类型组件输入内容前,显示在开始时间输入框中,用于提示的文字内容"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <el-input v-model="currentData.field_data.placeholder" placeholder="请输入起始提示文字" />
|
|
|
+ <div class="tips">
|
|
|
+ 结束提示文字
|
|
|
+ <guide
|
|
|
+ video="/static/guide/结束提示文字.jpg"
|
|
|
+ title="结束提示文字"
|
|
|
+ text="时间与日期类型组件输入内容前,显示在结束时间输入框中,用于提示的文字内容"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <el-input v-model="currentData.field_data.endPlaceholder" placeholder="请输入结束提示文字" />
|
|
|
+ <div class="tips">
|
|
|
+ 范围分隔符
|
|
|
+ <guide
|
|
|
+ video="/static/guide/范围分隔符.jpg"
|
|
|
+ title="范围分隔符"
|
|
|
+ text="时间与日期类型组件中,开始与结束提示文字中间的分隔文字。"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <el-input v-model="currentData.field_data.rangeSeparator" placeholder="请输入范围分隔符" />
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="['select','radio','checkbox'].includes(currentData.field_type)">
|
|
|
+ <div class="tips">
|
|
|
+ 选项设定
|
|
|
+ <guide
|
|
|
+ video="/static/guide/选项设定.mp4"
|
|
|
+ title="选项设定"
|
|
|
+ text="在单选、多选、选择器组件中,编辑可供用户选择的选择项目。"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="select-list">
|
|
|
+ <div class="item">
|
|
|
+ <draggable v-model="currentData.field_data.options" :options="{sort:true,animation:300}">
|
|
|
+ <transition-group class="select-inner">
|
|
|
+ <el-input v-for="(item,index) in currentData.field_data.options" :key="item.value" :value="item.label" disabled>
|
|
|
+ <div slot="prefix" class="handel">⠿</div>
|
|
|
+ <el-button slot="append" type="danger" icon="el-icon-delete" @click="removeSelectItem(index)" />
|
|
|
+ </el-input>
|
|
|
+ </transition-group>
|
|
|
+ </draggable>
|
|
|
+ <el-input v-model="selectInput" placeholder="请输入选项" @keyup.enter.native="addSelectItem">
|
|
|
+ <el-button slot="append" icon="el-icon-plus" @click="addSelectItem" />
|
|
|
+ </el-input>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="['number','slider'].includes(currentData.field_type)">
|
|
|
+ <div class="tips">
|
|
|
+ 最小值
|
|
|
+ <guide
|
|
|
+ video="/static/guide/最小值.jpg"
|
|
|
+ title="最小值"
|
|
|
+ text="数字输入类型的组件中,限制可以输入的最小数字。"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <el-input v-model="currentData.field_data.min" @change="currentData.field_data.value=$event-0" />
|
|
|
+ <div class="tips">
|
|
|
+ 最大值
|
|
|
+ <guide
|
|
|
+ video="/static/guide/最大值.jpg"
|
|
|
+ title="最大值"
|
|
|
+ text="数字输入类型的组件中,限制可以输入的最大数字。"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <el-input v-model="currentData.field_data.max" />
|
|
|
+ <div class="tips">
|
|
|
+ 步进值
|
|
|
+ <guide
|
|
|
+ video="/static/guide/步进值.mp4"
|
|
|
+ title="步进值"
|
|
|
+ text="数字输入类型的组件中,限制输入的数字为多少的倍数。"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <el-input v-model="currentData.field_data.step" />
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <div class="tips">
|
|
|
+ 组件宽度
|
|
|
+ <guide
|
|
|
+ video="/static/guide/组件宽度.mp4"
|
|
|
+ title="组件宽度"
|
|
|
+ text="设置所选定组件的宽度,有1/3、1/2、2/3、占据全部宽度,总共四种尺寸供选择。"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <el-radio-group v-model="currentData.field_data.width" size="small">
|
|
|
+ <el-radio-button :label="2">窄</el-radio-button>
|
|
|
+ <el-radio-button :label="3">中</el-radio-button>
|
|
|
+ <el-radio-button :label="4">宽</el-radio-button>
|
|
|
+ <el-radio-button :label="6">长</el-radio-button>
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.main-box{
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+ padding: 0 !important;
|
|
|
+ height: 100%;
|
|
|
+ width: 100%;
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 360px 1fr 360px;
|
|
|
+ grid-template-rows: 1fr;
|
|
|
+ .form-item{
|
|
|
+ background: white;
|
|
|
+ margin-bottom: -1px;
|
|
|
+ border-top: 1px solid lightgrey;
|
|
|
+ border-bottom: 1px solid lightgrey;
|
|
|
+ padding: 24px;
|
|
|
+ &.active{
|
|
|
+ animation: 300ms current linear infinite alternate;
|
|
|
+ }
|
|
|
+ @keyframes current {
|
|
|
+ 0%{
|
|
|
+ box-shadow: inset 0 0 0 3px #2563EBFF;
|
|
|
+ }
|
|
|
+ 100%{
|
|
|
+ box-shadow: inset 0 0 0 3px #2563EB88;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .tips{
|
|
|
+ font-size: 15px;
|
|
|
+ color: #989898;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ }
|
|
|
+ &.email{
|
|
|
+ .code-input{
|
|
|
+ display: flex;
|
|
|
+ grid-gap: 8px;
|
|
|
+ margin-top: 8px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.phone{
|
|
|
+ .phone-input{
|
|
|
+ display: flex;
|
|
|
+ grid-gap: 8px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.select{
|
|
|
+ .el-select{
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.number{
|
|
|
+ .el-input-number{
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.time,&.timeRange{
|
|
|
+ .el-date-editor{
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.date,&.dateRange{
|
|
|
+ .el-date-editor{
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.region{
|
|
|
+ .el-cascader{
|
|
|
+ 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;
|
|
|
+ .add{
|
|
|
+ position: absolute;
|
|
|
+ right: 32px;
|
|
|
+ bottom: 32px;
|
|
|
+ width: 56px;
|
|
|
+ height: 56px;
|
|
|
+ color: white;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ background-color: #2563EB;
|
|
|
+ border-radius: 50%;
|
|
|
+ font-size: 28px;
|
|
|
+ cursor: pointer;
|
|
|
+ z-index: 2;
|
|
|
+ transition-duration: 300ms;
|
|
|
+ &::after{
|
|
|
+ content: '添加组件';
|
|
|
+ position: absolute;
|
|
|
+ display: block;
|
|
|
+ padding: 8px 16px;
|
|
|
+ border-radius: 8px;
|
|
|
+ right: 68px;
|
|
|
+ text-align: center;
|
|
|
+ pointer-events: none;
|
|
|
+ opacity: 0;
|
|
|
+ transition-duration: 300ms;
|
|
|
+ color: white;
|
|
|
+ font-size: 16px;
|
|
|
+ width: 70px;
|
|
|
+ background-color: #409EFF;
|
|
|
+ }
|
|
|
+ &:hover{
|
|
|
+ box-shadow: 2px 2px 8px 2px #00000022;
|
|
|
+ scale: 1.04;
|
|
|
+ &::after{
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .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;
|
|
|
+ .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;
|
|
|
+ .title{
|
|
|
+ font-size: 36px;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+ .tips{
|
|
|
+ font-size: 20px;
|
|
|
+ color: #989898;
|
|
|
+ margin-bottom: 6px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .form-body{
|
|
|
+ .drag-cont{
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
|
|
|
+ width: 100%;
|
|
|
+ align-content: start;
|
|
|
+ .form-item{
|
|
|
+ outline: 3px dashed lightgray;
|
|
|
+ height: fit-content;
|
|
|
+ }
|
|
|
+ .required{
|
|
|
+ .tips{
|
|
|
+ &::after{
|
|
|
+ margin-left: 4px;
|
|
|
+ content: '*';
|
|
|
+ color: red;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .comp-edit{
|
|
|
+ z-index: 1;
|
|
|
+ position: relative;
|
|
|
+ box-shadow: 0 1px 4px 0 #00000022;
|
|
|
+ display: grid;
|
|
|
+ grid-template-rows: auto 1fr;
|
|
|
+ .body-cont{
|
|
|
+ position: relative;
|
|
|
+ height: calc(100% - 16px);
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ .body{
|
|
|
+ position: absolute;
|
|
|
+ overflow: hidden;
|
|
|
+ overflow-y: auto;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ height: 100%;
|
|
|
+ width: 100%;
|
|
|
+ padding: 0 16px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: flex-end;
|
|
|
+ .tips{
|
|
|
+ width: 100%;
|
|
|
+ font-size: 16px;
|
|
|
+ color: #505050;
|
|
|
+ margin-bottom: 6px;
|
|
|
+ margin-top: 12px;
|
|
|
+ }
|
|
|
+ .pattern-select{
|
|
|
+ margin-top: 6px;
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ .slider{
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ .select-list{
|
|
|
+ width: 100%;
|
|
|
+ .handel{
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+ .select-inner{
|
|
|
+ .el-input__inner{
|
|
|
+ cursor: grab;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .button{
|
|
|
+ gap: 12px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ padding: 16px;
|
|
|
+ }
|
|
|
+ .title{
|
|
|
+ padding: 16px;
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|
|
|
+<style>
|
|
|
+.copy-popover{
|
|
|
+ .body{
|
|
|
+ .content{
|
|
|
+ margin-bottom: 24px;
|
|
|
+ }
|
|
|
+ .button-list{
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|