Commit d2420212a68106da906d7d820cc59d61327a76cc
1 parent
00f96865
增加 Form 编辑框
Showing
7 changed files
with
2225 additions
and
1 deletions
yudao-admin-ui/src/router/index.js
| @@ -149,7 +149,20 @@ export const constantRoutes = [ | @@ -149,7 +149,20 @@ export const constantRoutes = [ | ||
| 149 | meta: { title: '请假表单-审批', icon: 'form' } | 149 | meta: { title: '请假表单-审批', icon: 'form' } |
| 150 | } | 150 | } |
| 151 | ] | 151 | ] |
| 152 | - } | 152 | + }, |
| 153 | + { | ||
| 154 | + path: '/bpm', | ||
| 155 | + component: Layout, | ||
| 156 | + hidden: true, | ||
| 157 | + children: [ | ||
| 158 | + { | ||
| 159 | + path: 'manager/form/edit', | ||
| 160 | + component: (resolve) => require(['@/views/bpm/form/build/index'], resolve), | ||
| 161 | + name: '流程表单-编辑', | ||
| 162 | + meta: { title: '流程表单-编辑' } | ||
| 163 | + } | ||
| 164 | + ] | ||
| 165 | + }, | ||
| 153 | ] | 166 | ] |
| 154 | 167 | ||
| 155 | export default new Router({ | 168 | export default new Router({ |
yudao-admin-ui/src/views/bpm/form/build/CodeTypeDialog.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <el-dialog | ||
| 4 | + v-bind="$attrs" | ||
| 5 | + width="500px" | ||
| 6 | + :close-on-click-modal="false" | ||
| 7 | + :modal-append-to-body="false" | ||
| 8 | + v-on="$listeners" | ||
| 9 | + @open="onOpen" | ||
| 10 | + @close="onClose" | ||
| 11 | + > | ||
| 12 | + <el-row :gutter="15"> | ||
| 13 | + <el-form | ||
| 14 | + ref="elForm" | ||
| 15 | + :model="formData" | ||
| 16 | + :rules="rules" | ||
| 17 | + size="medium" | ||
| 18 | + label-width="100px" | ||
| 19 | + > | ||
| 20 | + <el-col :span="24"> | ||
| 21 | + <el-form-item label="生成类型" prop="type"> | ||
| 22 | + <el-radio-group v-model="formData.type"> | ||
| 23 | + <el-radio-button | ||
| 24 | + v-for="(item, index) in typeOptions" | ||
| 25 | + :key="index" | ||
| 26 | + :label="item.value" | ||
| 27 | + :disabled="item.disabled" | ||
| 28 | + > | ||
| 29 | + {{ item.label }} | ||
| 30 | + </el-radio-button> | ||
| 31 | + </el-radio-group> | ||
| 32 | + </el-form-item> | ||
| 33 | + <el-form-item v-if="showFileName" label="文件名" prop="fileName"> | ||
| 34 | + <el-input v-model="formData.fileName" placeholder="请输入文件名" clearable /> | ||
| 35 | + </el-form-item> | ||
| 36 | + </el-col> | ||
| 37 | + </el-form> | ||
| 38 | + </el-row> | ||
| 39 | + | ||
| 40 | + <div slot="footer"> | ||
| 41 | + <el-button @click="close"> | ||
| 42 | + 取消 | ||
| 43 | + </el-button> | ||
| 44 | + <el-button type="primary" @click="handelConfirm"> | ||
| 45 | + 确定 | ||
| 46 | + </el-button> | ||
| 47 | + </div> | ||
| 48 | + </el-dialog> | ||
| 49 | + </div> | ||
| 50 | +</template> | ||
| 51 | +<script> | ||
| 52 | +export default { | ||
| 53 | + inheritAttrs: false, | ||
| 54 | + props: ['showFileName'], | ||
| 55 | + data() { | ||
| 56 | + return { | ||
| 57 | + formData: { | ||
| 58 | + fileName: undefined, | ||
| 59 | + type: 'file' | ||
| 60 | + }, | ||
| 61 | + rules: { | ||
| 62 | + fileName: [{ | ||
| 63 | + required: true, | ||
| 64 | + message: '请输入文件名', | ||
| 65 | + trigger: 'blur' | ||
| 66 | + }], | ||
| 67 | + type: [{ | ||
| 68 | + required: true, | ||
| 69 | + message: '生成类型不能为空', | ||
| 70 | + trigger: 'change' | ||
| 71 | + }] | ||
| 72 | + }, | ||
| 73 | + typeOptions: [{ | ||
| 74 | + label: '页面', | ||
| 75 | + value: 'file' | ||
| 76 | + }, { | ||
| 77 | + label: '弹窗', | ||
| 78 | + value: 'dialog' | ||
| 79 | + }] | ||
| 80 | + } | ||
| 81 | + }, | ||
| 82 | + computed: { | ||
| 83 | + }, | ||
| 84 | + watch: {}, | ||
| 85 | + mounted() {}, | ||
| 86 | + methods: { | ||
| 87 | + onOpen() { | ||
| 88 | + if (this.showFileName) { | ||
| 89 | + this.formData.fileName = `${+new Date()}.vue` | ||
| 90 | + } | ||
| 91 | + }, | ||
| 92 | + onClose() { | ||
| 93 | + }, | ||
| 94 | + close(e) { | ||
| 95 | + this.$emit('update:visible', false) | ||
| 96 | + }, | ||
| 97 | + handelConfirm() { | ||
| 98 | + this.$refs.elForm.validate(valid => { | ||
| 99 | + if (!valid) return | ||
| 100 | + this.$emit('confirm', { ...this.formData }) | ||
| 101 | + this.close() | ||
| 102 | + }) | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | +} | ||
| 106 | +</script> |
yudao-admin-ui/src/views/bpm/form/build/DraggableItem.vue
0 → 100644
| 1 | +<script> | ||
| 2 | +import draggable from 'vuedraggable' | ||
| 3 | +import render from '@/utils/generator/render' | ||
| 4 | + | ||
| 5 | +const components = { | ||
| 6 | + itemBtns(h, element, index, parent) { | ||
| 7 | + const { copyItem, deleteItem } = this.$listeners | ||
| 8 | + return [ | ||
| 9 | + <span class="drawing-item-copy" title="复制" onClick={event => { | ||
| 10 | + copyItem(element, parent); event.stopPropagation() | ||
| 11 | + }}> | ||
| 12 | + <i class="el-icon-copy-document" /> | ||
| 13 | + </span>, | ||
| 14 | + <span class="drawing-item-delete" title="删除" onClick={event => { | ||
| 15 | + deleteItem(index, parent); event.stopPropagation() | ||
| 16 | + }}> | ||
| 17 | + <i class="el-icon-delete" /> | ||
| 18 | + </span> | ||
| 19 | + ] | ||
| 20 | + } | ||
| 21 | +} | ||
| 22 | +const layouts = { | ||
| 23 | + colFormItem(h, element, index, parent) { | ||
| 24 | + const { activeItem } = this.$listeners | ||
| 25 | + let className = this.activeId === element.formId ? 'drawing-item active-from-item' : 'drawing-item' | ||
| 26 | + if (this.formConf.unFocusedComponentBorder) className += ' unfocus-bordered' | ||
| 27 | + return ( | ||
| 28 | + <el-col span={element.span} class={className} | ||
| 29 | + nativeOnClick={event => { activeItem(element); event.stopPropagation() }}> | ||
| 30 | + <el-form-item label-width={element.labelWidth ? `${element.labelWidth}px` : null} | ||
| 31 | + label={element.label} required={element.required}> | ||
| 32 | + <render key={element.renderKey} conf={element} onInput={ event => { | ||
| 33 | + this.$set(element, 'defaultValue', event) | ||
| 34 | + }} /> | ||
| 35 | + </el-form-item> | ||
| 36 | + {components.itemBtns.apply(this, arguments)} | ||
| 37 | + </el-col> | ||
| 38 | + ) | ||
| 39 | + }, | ||
| 40 | + rowFormItem(h, element, index, parent) { | ||
| 41 | + const { activeItem } = this.$listeners | ||
| 42 | + const className = this.activeId === element.formId ? 'drawing-row-item active-from-item' : 'drawing-row-item' | ||
| 43 | + let child = renderChildren.apply(this, arguments) | ||
| 44 | + if (element.type === 'flex') { | ||
| 45 | + child = <el-row type={element.type} justify={element.justify} align={element.align}> | ||
| 46 | + {child} | ||
| 47 | + </el-row> | ||
| 48 | + } | ||
| 49 | + return ( | ||
| 50 | + <el-col span={element.span}> | ||
| 51 | + <el-row gutter={element.gutter} class={className} | ||
| 52 | + nativeOnClick={event => { activeItem(element); event.stopPropagation() }}> | ||
| 53 | + <span class="component-name">{element.componentName}</span> | ||
| 54 | + <draggable list={element.children} animation={340} group="componentsGroup" class="drag-wrapper"> | ||
| 55 | + {child} | ||
| 56 | + </draggable> | ||
| 57 | + {components.itemBtns.apply(this, arguments)} | ||
| 58 | + </el-row> | ||
| 59 | + </el-col> | ||
| 60 | + ) | ||
| 61 | + } | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +function renderChildren(h, element, index, parent) { | ||
| 65 | + if (!Array.isArray(element.children)) return null | ||
| 66 | + return element.children.map((el, i) => { | ||
| 67 | + const layout = layouts[el.layout] | ||
| 68 | + if (layout) { | ||
| 69 | + return layout.call(this, h, el, i, element.children) | ||
| 70 | + } | ||
| 71 | + return layoutIsNotFound() | ||
| 72 | + }) | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +function layoutIsNotFound() { | ||
| 76 | + throw new Error(`没有与${this.element.layout}匹配的layout`) | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +export default { | ||
| 80 | + components: { | ||
| 81 | + render, | ||
| 82 | + draggable | ||
| 83 | + }, | ||
| 84 | + props: [ | ||
| 85 | + 'element', | ||
| 86 | + 'index', | ||
| 87 | + 'drawingList', | ||
| 88 | + 'activeId', | ||
| 89 | + 'formConf' | ||
| 90 | + ], | ||
| 91 | + render(h) { | ||
| 92 | + const layout = layouts[this.element.layout] | ||
| 93 | + | ||
| 94 | + if (layout) { | ||
| 95 | + return layout.call(this, h, this.element, this.index, this.drawingList) | ||
| 96 | + } | ||
| 97 | + return layoutIsNotFound() | ||
| 98 | + } | ||
| 99 | +} | ||
| 100 | +</script> |
yudao-admin-ui/src/views/bpm/form/build/IconsDialog.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="icon-dialog"> | ||
| 3 | + <el-dialog | ||
| 4 | + v-bind="$attrs" | ||
| 5 | + width="980px" | ||
| 6 | + :modal-append-to-body="false" | ||
| 7 | + v-on="$listeners" | ||
| 8 | + @open="onOpen" | ||
| 9 | + @close="onClose" | ||
| 10 | + > | ||
| 11 | + <div slot="title"> | ||
| 12 | + 选择图标 | ||
| 13 | + <el-input | ||
| 14 | + v-model="key" | ||
| 15 | + size="mini" | ||
| 16 | + :style="{width: '260px'}" | ||
| 17 | + placeholder="请输入图标名称" | ||
| 18 | + prefix-icon="el-icon-search" | ||
| 19 | + clearable | ||
| 20 | + /> | ||
| 21 | + </div> | ||
| 22 | + <ul class="icon-ul"> | ||
| 23 | + <li | ||
| 24 | + v-for="icon in iconList" | ||
| 25 | + :key="icon" | ||
| 26 | + :class="active===icon?'active-item':''" | ||
| 27 | + @click="onSelect(icon)" | ||
| 28 | + > | ||
| 29 | + <i :class="icon" /> | ||
| 30 | + <div>{{ icon }}</div> | ||
| 31 | + </li> | ||
| 32 | + </ul> | ||
| 33 | + </el-dialog> | ||
| 34 | + </div> | ||
| 35 | +</template> | ||
| 36 | +<script> | ||
| 37 | +import iconList from '@/utils/generator/icon.json' | ||
| 38 | + | ||
| 39 | +const originList = iconList.map(name => `el-icon-${name}`) | ||
| 40 | + | ||
| 41 | +export default { | ||
| 42 | + inheritAttrs: false, | ||
| 43 | + props: ['current'], | ||
| 44 | + data() { | ||
| 45 | + return { | ||
| 46 | + iconList: originList, | ||
| 47 | + active: null, | ||
| 48 | + key: '' | ||
| 49 | + } | ||
| 50 | + }, | ||
| 51 | + watch: { | ||
| 52 | + key(val) { | ||
| 53 | + if (val) { | ||
| 54 | + this.iconList = originList.filter(name => name.indexOf(val) > -1) | ||
| 55 | + } else { | ||
| 56 | + this.iconList = originList | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + }, | ||
| 60 | + methods: { | ||
| 61 | + onOpen() { | ||
| 62 | + this.active = this.current | ||
| 63 | + this.key = '' | ||
| 64 | + }, | ||
| 65 | + onClose() {}, | ||
| 66 | + onSelect(icon) { | ||
| 67 | + this.active = icon | ||
| 68 | + this.$emit('select', icon) | ||
| 69 | + this.$emit('update:visible', false) | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | +} | ||
| 73 | +</script> | ||
| 74 | +<style lang="scss" scoped> | ||
| 75 | +.icon-ul { | ||
| 76 | + margin: 0; | ||
| 77 | + padding: 0; | ||
| 78 | + font-size: 0; | ||
| 79 | + li { | ||
| 80 | + list-style-type: none; | ||
| 81 | + text-align: center; | ||
| 82 | + font-size: 14px; | ||
| 83 | + display: inline-block; | ||
| 84 | + width: 16.66%; | ||
| 85 | + box-sizing: border-box; | ||
| 86 | + height: 108px; | ||
| 87 | + padding: 15px 6px 6px 6px; | ||
| 88 | + cursor: pointer; | ||
| 89 | + overflow: hidden; | ||
| 90 | + &:hover { | ||
| 91 | + background: #f2f2f2; | ||
| 92 | + } | ||
| 93 | + &.active-item{ | ||
| 94 | + background: #e1f3fb; | ||
| 95 | + color: #7a6df0 | ||
| 96 | + } | ||
| 97 | + > i { | ||
| 98 | + font-size: 30px; | ||
| 99 | + line-height: 50px; | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | +} | ||
| 103 | +.icon-dialog { | ||
| 104 | + ::v-deep .el-dialog { | ||
| 105 | + border-radius: 8px; | ||
| 106 | + margin-bottom: 0; | ||
| 107 | + margin-top: 4vh !important; | ||
| 108 | + display: flex; | ||
| 109 | + flex-direction: column; | ||
| 110 | + max-height: 92vh; | ||
| 111 | + overflow: hidden; | ||
| 112 | + box-sizing: border-box; | ||
| 113 | + .el-dialog__header { | ||
| 114 | + padding-top: 14px; | ||
| 115 | + } | ||
| 116 | + .el-dialog__body { | ||
| 117 | + margin: 0 20px 20px 20px; | ||
| 118 | + padding: 0; | ||
| 119 | + overflow: auto; | ||
| 120 | + } | ||
| 121 | + } | ||
| 122 | +} | ||
| 123 | +</style> |
yudao-admin-ui/src/views/bpm/form/build/RightPanel.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="right-board"> | ||
| 3 | + <el-tabs v-model="currentTab" class="center-tabs"> | ||
| 4 | + <el-tab-pane label="组件属性" name="field" /> | ||
| 5 | + <el-tab-pane label="表单属性" name="form" /> | ||
| 6 | + </el-tabs> | ||
| 7 | + <div class="field-box"> | ||
| 8 | + <a class="document-link" target="_blank" :href="documentLink" title="查看组件文档"> | ||
| 9 | + <i class="el-icon-link" /> | ||
| 10 | + </a> | ||
| 11 | + <el-scrollbar class="right-scrollbar"> | ||
| 12 | + <!-- 组件属性 --> | ||
| 13 | + <el-form v-show="currentTab==='field' && showField" size="small" label-width="90px"> | ||
| 14 | + <el-form-item v-if="activeData.changeTag" label="组件类型"> | ||
| 15 | + <el-select | ||
| 16 | + v-model="activeData.tagIcon" | ||
| 17 | + placeholder="请选择组件类型" | ||
| 18 | + :style="{width: '100%'}" | ||
| 19 | + @change="tagChange" | ||
| 20 | + > | ||
| 21 | + <el-option-group v-for="group in tagList" :key="group.label" :label="group.label"> | ||
| 22 | + <el-option | ||
| 23 | + v-for="item in group.options" | ||
| 24 | + :key="item.label" | ||
| 25 | + :label="item.label" | ||
| 26 | + :value="item.tagIcon" | ||
| 27 | + > | ||
| 28 | + <svg-icon class="node-icon" :icon-class="item.tagIcon" /> | ||
| 29 | + <span> {{ item.label }}</span> | ||
| 30 | + </el-option> | ||
| 31 | + </el-option-group> | ||
| 32 | + </el-select> | ||
| 33 | + </el-form-item> | ||
| 34 | + <el-form-item v-if="activeData.vModel!==undefined" label="字段名"> | ||
| 35 | + <el-input v-model="activeData.vModel" placeholder="请输入字段名(v-model)" /> | ||
| 36 | + </el-form-item> | ||
| 37 | + <el-form-item v-if="activeData.componentName!==undefined" label="组件名"> | ||
| 38 | + {{ activeData.componentName }} | ||
| 39 | + </el-form-item> | ||
| 40 | + <el-form-item v-if="activeData.label!==undefined" label="标题"> | ||
| 41 | + <el-input v-model="activeData.label" placeholder="请输入标题" /> | ||
| 42 | + </el-form-item> | ||
| 43 | + <el-form-item v-if="activeData.placeholder!==undefined" label="占位提示"> | ||
| 44 | + <el-input v-model="activeData.placeholder" placeholder="请输入占位提示" /> | ||
| 45 | + </el-form-item> | ||
| 46 | + <el-form-item v-if="activeData['start-placeholder']!==undefined" label="开始占位"> | ||
| 47 | + <el-input v-model="activeData['start-placeholder']" placeholder="请输入占位提示" /> | ||
| 48 | + </el-form-item> | ||
| 49 | + <el-form-item v-if="activeData['end-placeholder']!==undefined" label="结束占位"> | ||
| 50 | + <el-input v-model="activeData['end-placeholder']" placeholder="请输入占位提示" /> | ||
| 51 | + </el-form-item> | ||
| 52 | + <el-form-item v-if="activeData.span!==undefined" label="表单栅格"> | ||
| 53 | + <el-slider v-model="activeData.span" :max="24" :min="1" :marks="{12:''}" @change="spanChange" /> | ||
| 54 | + </el-form-item> | ||
| 55 | + <el-form-item v-if="activeData.layout==='rowFormItem'" label="栅格间隔"> | ||
| 56 | + <el-input-number v-model="activeData.gutter" :min="0" placeholder="栅格间隔" /> | ||
| 57 | + </el-form-item> | ||
| 58 | + <el-form-item v-if="activeData.layout==='rowFormItem'" label="布局模式"> | ||
| 59 | + <el-radio-group v-model="activeData.type"> | ||
| 60 | + <el-radio-button label="default" /> | ||
| 61 | + <el-radio-button label="flex" /> | ||
| 62 | + </el-radio-group> | ||
| 63 | + </el-form-item> | ||
| 64 | + <el-form-item v-if="activeData.justify!==undefined&&activeData.type==='flex'" label="水平排列"> | ||
| 65 | + <el-select v-model="activeData.justify" placeholder="请选择水平排列" :style="{width: '100%'}"> | ||
| 66 | + <el-option | ||
| 67 | + v-for="(item, index) in justifyOptions" | ||
| 68 | + :key="index" | ||
| 69 | + :label="item.label" | ||
| 70 | + :value="item.value" | ||
| 71 | + /> | ||
| 72 | + </el-select> | ||
| 73 | + </el-form-item> | ||
| 74 | + <el-form-item v-if="activeData.align!==undefined&&activeData.type==='flex'" label="垂直排列"> | ||
| 75 | + <el-radio-group v-model="activeData.align"> | ||
| 76 | + <el-radio-button label="top" /> | ||
| 77 | + <el-radio-button label="middle" /> | ||
| 78 | + <el-radio-button label="bottom" /> | ||
| 79 | + </el-radio-group> | ||
| 80 | + </el-form-item> | ||
| 81 | + <el-form-item v-if="activeData.labelWidth!==undefined" label="标签宽度"> | ||
| 82 | + <el-input v-model.number="activeData.labelWidth" type="number" placeholder="请输入标签宽度" /> | ||
| 83 | + </el-form-item> | ||
| 84 | + <el-form-item v-if="activeData.style&&activeData.style.width!==undefined" label="组件宽度"> | ||
| 85 | + <el-input v-model="activeData.style.width" placeholder="请输入组件宽度" clearable /> | ||
| 86 | + </el-form-item> | ||
| 87 | + <el-form-item v-if="activeData.vModel!==undefined" label="默认值"> | ||
| 88 | + <el-input | ||
| 89 | + :value="setDefaultValue(activeData.defaultValue)" | ||
| 90 | + placeholder="请输入默认值" | ||
| 91 | + @input="onDefaultValueInput" | ||
| 92 | + /> | ||
| 93 | + </el-form-item> | ||
| 94 | + <el-form-item v-if="activeData.tag==='el-checkbox-group'" label="至少应选"> | ||
| 95 | + <el-input-number | ||
| 96 | + :value="activeData.min" | ||
| 97 | + :min="0" | ||
| 98 | + placeholder="至少应选" | ||
| 99 | + @input="$set(activeData, 'min', $event?$event:undefined)" | ||
| 100 | + /> | ||
| 101 | + </el-form-item> | ||
| 102 | + <el-form-item v-if="activeData.tag==='el-checkbox-group'" label="最多可选"> | ||
| 103 | + <el-input-number | ||
| 104 | + :value="activeData.max" | ||
| 105 | + :min="0" | ||
| 106 | + placeholder="最多可选" | ||
| 107 | + @input="$set(activeData, 'max', $event?$event:undefined)" | ||
| 108 | + /> | ||
| 109 | + </el-form-item> | ||
| 110 | + <el-form-item v-if="activeData.prepend!==undefined" label="前缀"> | ||
| 111 | + <el-input v-model="activeData.prepend" placeholder="请输入前缀" /> | ||
| 112 | + </el-form-item> | ||
| 113 | + <el-form-item v-if="activeData.append!==undefined" label="后缀"> | ||
| 114 | + <el-input v-model="activeData.append" placeholder="请输入后缀" /> | ||
| 115 | + </el-form-item> | ||
| 116 | + <el-form-item v-if="activeData['prefix-icon']!==undefined" label="前图标"> | ||
| 117 | + <el-input v-model="activeData['prefix-icon']" placeholder="请输入前图标名称"> | ||
| 118 | + <el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('prefix-icon')"> | ||
| 119 | + 选择 | ||
| 120 | + </el-button> | ||
| 121 | + </el-input> | ||
| 122 | + </el-form-item> | ||
| 123 | + <el-form-item v-if="activeData['suffix-icon'] !== undefined" label="后图标"> | ||
| 124 | + <el-input v-model="activeData['suffix-icon']" placeholder="请输入后图标名称"> | ||
| 125 | + <el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('suffix-icon')"> | ||
| 126 | + 选择 | ||
| 127 | + </el-button> | ||
| 128 | + </el-input> | ||
| 129 | + </el-form-item> | ||
| 130 | + <el-form-item v-if="activeData.tag === 'el-cascader'" label="选项分隔符"> | ||
| 131 | + <el-input v-model="activeData.separator" placeholder="请输入选项分隔符" /> | ||
| 132 | + </el-form-item> | ||
| 133 | + <el-form-item v-if="activeData.autosize !== undefined" label="最小行数"> | ||
| 134 | + <el-input-number v-model="activeData.autosize.minRows" :min="1" placeholder="最小行数" /> | ||
| 135 | + </el-form-item> | ||
| 136 | + <el-form-item v-if="activeData.autosize !== undefined" label="最大行数"> | ||
| 137 | + <el-input-number v-model="activeData.autosize.maxRows" :min="1" placeholder="最大行数" /> | ||
| 138 | + </el-form-item> | ||
| 139 | + <el-form-item v-if="activeData.min !== undefined" label="最小值"> | ||
| 140 | + <el-input-number v-model="activeData.min" placeholder="最小值" /> | ||
| 141 | + </el-form-item> | ||
| 142 | + <el-form-item v-if="activeData.max !== undefined" label="最大值"> | ||
| 143 | + <el-input-number v-model="activeData.max" placeholder="最大值" /> | ||
| 144 | + </el-form-item> | ||
| 145 | + <el-form-item v-if="activeData.step !== undefined" label="步长"> | ||
| 146 | + <el-input-number v-model="activeData.step" placeholder="步数" /> | ||
| 147 | + </el-form-item> | ||
| 148 | + <el-form-item v-if="activeData.tag === 'el-input-number'" label="精度"> | ||
| 149 | + <el-input-number v-model="activeData.precision" :min="0" placeholder="精度" /> | ||
| 150 | + </el-form-item> | ||
| 151 | + <el-form-item v-if="activeData.tag === 'el-input-number'" label="按钮位置"> | ||
| 152 | + <el-radio-group v-model="activeData['controls-position']"> | ||
| 153 | + <el-radio-button label=""> | ||
| 154 | + 默认 | ||
| 155 | + </el-radio-button> | ||
| 156 | + <el-radio-button label="right"> | ||
| 157 | + 右侧 | ||
| 158 | + </el-radio-button> | ||
| 159 | + </el-radio-group> | ||
| 160 | + </el-form-item> | ||
| 161 | + <el-form-item v-if="activeData.maxlength !== undefined" label="最多输入"> | ||
| 162 | + <el-input v-model="activeData.maxlength" placeholder="请输入字符长度"> | ||
| 163 | + <template slot="append"> | ||
| 164 | + 个字符 | ||
| 165 | + </template> | ||
| 166 | + </el-input> | ||
| 167 | + </el-form-item> | ||
| 168 | + <el-form-item v-if="activeData['active-text'] !== undefined" label="开启提示"> | ||
| 169 | + <el-input v-model="activeData['active-text']" placeholder="请输入开启提示" /> | ||
| 170 | + </el-form-item> | ||
| 171 | + <el-form-item v-if="activeData['inactive-text'] !== undefined" label="关闭提示"> | ||
| 172 | + <el-input v-model="activeData['inactive-text']" placeholder="请输入关闭提示" /> | ||
| 173 | + </el-form-item> | ||
| 174 | + <el-form-item v-if="activeData['active-value'] !== undefined" label="开启值"> | ||
| 175 | + <el-input | ||
| 176 | + :value="setDefaultValue(activeData['active-value'])" | ||
| 177 | + placeholder="请输入开启值" | ||
| 178 | + @input="onSwitchValueInput($event, 'active-value')" | ||
| 179 | + /> | ||
| 180 | + </el-form-item> | ||
| 181 | + <el-form-item v-if="activeData['inactive-value'] !== undefined" label="关闭值"> | ||
| 182 | + <el-input | ||
| 183 | + :value="setDefaultValue(activeData['inactive-value'])" | ||
| 184 | + placeholder="请输入关闭值" | ||
| 185 | + @input="onSwitchValueInput($event, 'inactive-value')" | ||
| 186 | + /> | ||
| 187 | + </el-form-item> | ||
| 188 | + <el-form-item | ||
| 189 | + v-if="activeData.type !== undefined && 'el-date-picker' === activeData.tag" | ||
| 190 | + label="时间类型" | ||
| 191 | + > | ||
| 192 | + <el-select | ||
| 193 | + v-model="activeData.type" | ||
| 194 | + placeholder="请选择时间类型" | ||
| 195 | + :style="{ width: '100%' }" | ||
| 196 | + @change="dateTypeChange" | ||
| 197 | + > | ||
| 198 | + <el-option | ||
| 199 | + v-for="(item, index) in dateOptions" | ||
| 200 | + :key="index" | ||
| 201 | + :label="item.label" | ||
| 202 | + :value="item.value" | ||
| 203 | + /> | ||
| 204 | + </el-select> | ||
| 205 | + </el-form-item> | ||
| 206 | + <el-form-item v-if="activeData.name !== undefined" label="文件字段名"> | ||
| 207 | + <el-input v-model="activeData.name" placeholder="请输入上传文件字段名" /> | ||
| 208 | + </el-form-item> | ||
| 209 | + <el-form-item v-if="activeData.accept !== undefined" label="文件类型"> | ||
| 210 | + <el-select | ||
| 211 | + v-model="activeData.accept" | ||
| 212 | + placeholder="请选择文件类型" | ||
| 213 | + :style="{ width: '100%' }" | ||
| 214 | + clearable | ||
| 215 | + > | ||
| 216 | + <el-option label="图片" value="image/*" /> | ||
| 217 | + <el-option label="视频" value="video/*" /> | ||
| 218 | + <el-option label="音频" value="audio/*" /> | ||
| 219 | + <el-option label="excel" value=".xls,.xlsx" /> | ||
| 220 | + <el-option label="word" value=".doc,.docx" /> | ||
| 221 | + <el-option label="pdf" value=".pdf" /> | ||
| 222 | + <el-option label="txt" value=".txt" /> | ||
| 223 | + </el-select> | ||
| 224 | + </el-form-item> | ||
| 225 | + <el-form-item v-if="activeData.fileSize !== undefined" label="文件大小"> | ||
| 226 | + <el-input v-model.number="activeData.fileSize" placeholder="请输入文件大小"> | ||
| 227 | + <el-select slot="append" v-model="activeData.sizeUnit" :style="{ width: '66px' }"> | ||
| 228 | + <el-option label="KB" value="KB" /> | ||
| 229 | + <el-option label="MB" value="MB" /> | ||
| 230 | + <el-option label="GB" value="GB" /> | ||
| 231 | + </el-select> | ||
| 232 | + </el-input> | ||
| 233 | + </el-form-item> | ||
| 234 | + <el-form-item v-if="activeData.action !== undefined" label="上传地址"> | ||
| 235 | + <el-input v-model="activeData.action" placeholder="请输入上传地址" clearable /> | ||
| 236 | + </el-form-item> | ||
| 237 | + <el-form-item v-if="activeData['list-type'] !== undefined" label="列表类型"> | ||
| 238 | + <el-radio-group v-model="activeData['list-type']" size="small"> | ||
| 239 | + <el-radio-button label="text"> | ||
| 240 | + text | ||
| 241 | + </el-radio-button> | ||
| 242 | + <el-radio-button label="picture"> | ||
| 243 | + picture | ||
| 244 | + </el-radio-button> | ||
| 245 | + <el-radio-button label="picture-card"> | ||
| 246 | + picture-card | ||
| 247 | + </el-radio-button> | ||
| 248 | + </el-radio-group> | ||
| 249 | + </el-form-item> | ||
| 250 | + <el-form-item | ||
| 251 | + v-if="activeData.buttonText !== undefined" | ||
| 252 | + v-show="'picture-card' !== activeData['list-type']" | ||
| 253 | + label="按钮文字" | ||
| 254 | + > | ||
| 255 | + <el-input v-model="activeData.buttonText" placeholder="请输入按钮文字" /> | ||
| 256 | + </el-form-item> | ||
| 257 | + <el-form-item v-if="activeData['range-separator'] !== undefined" label="分隔符"> | ||
| 258 | + <el-input v-model="activeData['range-separator']" placeholder="请输入分隔符" /> | ||
| 259 | + </el-form-item> | ||
| 260 | + <el-form-item v-if="activeData['picker-options'] !== undefined" label="时间段"> | ||
| 261 | + <el-input | ||
| 262 | + v-model="activeData['picker-options'].selectableRange" | ||
| 263 | + placeholder="请输入时间段" | ||
| 264 | + /> | ||
| 265 | + </el-form-item> | ||
| 266 | + <el-form-item v-if="activeData.format !== undefined" label="时间格式"> | ||
| 267 | + <el-input | ||
| 268 | + :value="activeData.format" | ||
| 269 | + placeholder="请输入时间格式" | ||
| 270 | + @input="setTimeValue($event)" | ||
| 271 | + /> | ||
| 272 | + </el-form-item> | ||
| 273 | + <template v-if="['el-checkbox-group', 'el-radio-group', 'el-select'].indexOf(activeData.tag) > -1"> | ||
| 274 | + <el-divider>选项</el-divider> | ||
| 275 | + <draggable | ||
| 276 | + :list="activeData.options" | ||
| 277 | + :animation="340" | ||
| 278 | + group="selectItem" | ||
| 279 | + handle=".option-drag" | ||
| 280 | + > | ||
| 281 | + <div v-for="(item, index) in activeData.options" :key="index" class="select-item"> | ||
| 282 | + <div class="select-line-icon option-drag"> | ||
| 283 | + <i class="el-icon-s-operation" /> | ||
| 284 | + </div> | ||
| 285 | + <el-input v-model="item.label" placeholder="选项名" size="small" /> | ||
| 286 | + <el-input | ||
| 287 | + placeholder="选项值" | ||
| 288 | + size="small" | ||
| 289 | + :value="item.value" | ||
| 290 | + @input="setOptionValue(item, $event)" | ||
| 291 | + /> | ||
| 292 | + <div class="close-btn select-line-icon" @click="activeData.options.splice(index, 1)"> | ||
| 293 | + <i class="el-icon-remove-outline" /> | ||
| 294 | + </div> | ||
| 295 | + </div> | ||
| 296 | + </draggable> | ||
| 297 | + <div style="margin-left: 20px;"> | ||
| 298 | + <el-button | ||
| 299 | + style="padding-bottom: 0" | ||
| 300 | + icon="el-icon-circle-plus-outline" | ||
| 301 | + type="text" | ||
| 302 | + @click="addSelectItem" | ||
| 303 | + > | ||
| 304 | + 添加选项 | ||
| 305 | + </el-button> | ||
| 306 | + </div> | ||
| 307 | + <el-divider /> | ||
| 308 | + </template> | ||
| 309 | + | ||
| 310 | + <template v-if="['el-cascader'].indexOf(activeData.tag) > -1"> | ||
| 311 | + <el-divider>选项</el-divider> | ||
| 312 | + <el-form-item label="数据类型"> | ||
| 313 | + <el-radio-group v-model="activeData.dataType" size="small"> | ||
| 314 | + <el-radio-button label="dynamic"> | ||
| 315 | + 动态数据 | ||
| 316 | + </el-radio-button> | ||
| 317 | + <el-radio-button label="static"> | ||
| 318 | + 静态数据 | ||
| 319 | + </el-radio-button> | ||
| 320 | + </el-radio-group> | ||
| 321 | + </el-form-item> | ||
| 322 | + | ||
| 323 | + <template v-if="activeData.dataType === 'dynamic'"> | ||
| 324 | + <el-form-item label="标签键名"> | ||
| 325 | + <el-input v-model="activeData.labelKey" placeholder="请输入标签键名" /> | ||
| 326 | + </el-form-item> | ||
| 327 | + <el-form-item label="值键名"> | ||
| 328 | + <el-input v-model="activeData.valueKey" placeholder="请输入值键名" /> | ||
| 329 | + </el-form-item> | ||
| 330 | + <el-form-item label="子级键名"> | ||
| 331 | + <el-input v-model="activeData.childrenKey" placeholder="请输入子级键名" /> | ||
| 332 | + </el-form-item> | ||
| 333 | + </template> | ||
| 334 | + | ||
| 335 | + <el-tree | ||
| 336 | + v-if="activeData.dataType === 'static'" | ||
| 337 | + draggable | ||
| 338 | + :data="activeData.options" | ||
| 339 | + node-key="id" | ||
| 340 | + :expand-on-click-node="false" | ||
| 341 | + :render-content="renderContent" | ||
| 342 | + /> | ||
| 343 | + <div v-if="activeData.dataType === 'static'" style="margin-left: 20px"> | ||
| 344 | + <el-button | ||
| 345 | + style="padding-bottom: 0" | ||
| 346 | + icon="el-icon-circle-plus-outline" | ||
| 347 | + type="text" | ||
| 348 | + @click="addTreeItem" | ||
| 349 | + > | ||
| 350 | + 添加父级 | ||
| 351 | + </el-button> | ||
| 352 | + </div> | ||
| 353 | + <el-divider /> | ||
| 354 | + </template> | ||
| 355 | + | ||
| 356 | + <el-form-item v-if="activeData.optionType !== undefined" label="选项样式"> | ||
| 357 | + <el-radio-group v-model="activeData.optionType"> | ||
| 358 | + <el-radio-button label="default"> | ||
| 359 | + 默认 | ||
| 360 | + </el-radio-button> | ||
| 361 | + <el-radio-button label="button"> | ||
| 362 | + 按钮 | ||
| 363 | + </el-radio-button> | ||
| 364 | + </el-radio-group> | ||
| 365 | + </el-form-item> | ||
| 366 | + <el-form-item v-if="activeData['active-color'] !== undefined" label="开启颜色"> | ||
| 367 | + <el-color-picker v-model="activeData['active-color']" /> | ||
| 368 | + </el-form-item> | ||
| 369 | + <el-form-item v-if="activeData['inactive-color'] !== undefined" label="关闭颜色"> | ||
| 370 | + <el-color-picker v-model="activeData['inactive-color']" /> | ||
| 371 | + </el-form-item> | ||
| 372 | + | ||
| 373 | + <el-form-item v-if="activeData['allow-half'] !== undefined" label="允许半选"> | ||
| 374 | + <el-switch v-model="activeData['allow-half']" /> | ||
| 375 | + </el-form-item> | ||
| 376 | + <el-form-item v-if="activeData['show-text'] !== undefined" label="辅助文字"> | ||
| 377 | + <el-switch v-model="activeData['show-text']" @change="rateTextChange" /> | ||
| 378 | + </el-form-item> | ||
| 379 | + <el-form-item v-if="activeData['show-score'] !== undefined" label="显示分数"> | ||
| 380 | + <el-switch v-model="activeData['show-score']" @change="rateScoreChange" /> | ||
| 381 | + </el-form-item> | ||
| 382 | + <el-form-item v-if="activeData['show-stops'] !== undefined" label="显示间断点"> | ||
| 383 | + <el-switch v-model="activeData['show-stops']" /> | ||
| 384 | + </el-form-item> | ||
| 385 | + <el-form-item v-if="activeData.range !== undefined" label="范围选择"> | ||
| 386 | + <el-switch v-model="activeData.range" @change="rangeChange" /> | ||
| 387 | + </el-form-item> | ||
| 388 | + <el-form-item | ||
| 389 | + v-if="activeData.border !== undefined && activeData.optionType === 'default'" | ||
| 390 | + label="是否带边框" | ||
| 391 | + > | ||
| 392 | + <el-switch v-model="activeData.border" /> | ||
| 393 | + </el-form-item> | ||
| 394 | + <el-form-item v-if="activeData.tag === 'el-color-picker'" label="颜色格式"> | ||
| 395 | + <el-select | ||
| 396 | + v-model="activeData['color-format']" | ||
| 397 | + placeholder="请选择颜色格式" | ||
| 398 | + :style="{ width: '100%' }" | ||
| 399 | + @change="colorFormatChange" | ||
| 400 | + > | ||
| 401 | + <el-option | ||
| 402 | + v-for="(item, index) in colorFormatOptions" | ||
| 403 | + :key="index" | ||
| 404 | + :label="item.label" | ||
| 405 | + :value="item.value" | ||
| 406 | + /> | ||
| 407 | + </el-select> | ||
| 408 | + </el-form-item> | ||
| 409 | + <el-form-item | ||
| 410 | + v-if="activeData.size !== undefined && | ||
| 411 | + (activeData.optionType === 'button' || | ||
| 412 | + activeData.border || | ||
| 413 | + activeData.tag === 'el-color-picker')" | ||
| 414 | + label="选项尺寸" | ||
| 415 | + > | ||
| 416 | + <el-radio-group v-model="activeData.size"> | ||
| 417 | + <el-radio-button label="medium"> | ||
| 418 | + 中等 | ||
| 419 | + </el-radio-button> | ||
| 420 | + <el-radio-button label="small"> | ||
| 421 | + 较小 | ||
| 422 | + </el-radio-button> | ||
| 423 | + <el-radio-button label="mini"> | ||
| 424 | + 迷你 | ||
| 425 | + </el-radio-button> | ||
| 426 | + </el-radio-group> | ||
| 427 | + </el-form-item> | ||
| 428 | + <el-form-item v-if="activeData['show-word-limit'] !== undefined" label="输入统计"> | ||
| 429 | + <el-switch v-model="activeData['show-word-limit']" /> | ||
| 430 | + </el-form-item> | ||
| 431 | + <el-form-item v-if="activeData.tag === 'el-input-number'" label="严格步数"> | ||
| 432 | + <el-switch v-model="activeData['step-strictly']" /> | ||
| 433 | + </el-form-item> | ||
| 434 | + <el-form-item v-if="activeData.tag === 'el-cascader'" label="是否多选"> | ||
| 435 | + <el-switch v-model="activeData.props.props.multiple" /> | ||
| 436 | + </el-form-item> | ||
| 437 | + <el-form-item v-if="activeData.tag === 'el-cascader'" label="展示全路径"> | ||
| 438 | + <el-switch v-model="activeData['show-all-levels']" /> | ||
| 439 | + </el-form-item> | ||
| 440 | + <el-form-item v-if="activeData.tag === 'el-cascader'" label="可否筛选"> | ||
| 441 | + <el-switch v-model="activeData.filterable" /> | ||
| 442 | + </el-form-item> | ||
| 443 | + <el-form-item v-if="activeData.clearable !== undefined" label="能否清空"> | ||
| 444 | + <el-switch v-model="activeData.clearable" /> | ||
| 445 | + </el-form-item> | ||
| 446 | + <el-form-item v-if="activeData.showTip !== undefined" label="显示提示"> | ||
| 447 | + <el-switch v-model="activeData.showTip" /> | ||
| 448 | + </el-form-item> | ||
| 449 | + <el-form-item v-if="activeData.multiple !== undefined" label="多选文件"> | ||
| 450 | + <el-switch v-model="activeData.multiple" /> | ||
| 451 | + </el-form-item> | ||
| 452 | + <el-form-item v-if="activeData['auto-upload'] !== undefined" label="自动上传"> | ||
| 453 | + <el-switch v-model="activeData['auto-upload']" /> | ||
| 454 | + </el-form-item> | ||
| 455 | + <el-form-item v-if="activeData.readonly !== undefined" label="是否只读"> | ||
| 456 | + <el-switch v-model="activeData.readonly" /> | ||
| 457 | + </el-form-item> | ||
| 458 | + <el-form-item v-if="activeData.disabled !== undefined" label="是否禁用"> | ||
| 459 | + <el-switch v-model="activeData.disabled" /> | ||
| 460 | + </el-form-item> | ||
| 461 | + <el-form-item v-if="activeData.tag === 'el-select'" label="是否可搜索"> | ||
| 462 | + <el-switch v-model="activeData.filterable" /> | ||
| 463 | + </el-form-item> | ||
| 464 | + <el-form-item v-if="activeData.tag === 'el-select'" label="是否多选"> | ||
| 465 | + <el-switch v-model="activeData.multiple" @change="multipleChange" /> | ||
| 466 | + </el-form-item> | ||
| 467 | + <el-form-item v-if="activeData.required !== undefined" label="是否必填"> | ||
| 468 | + <el-switch v-model="activeData.required" /> | ||
| 469 | + </el-form-item> | ||
| 470 | + | ||
| 471 | + <template v-if="activeData.layoutTree"> | ||
| 472 | + <el-divider>布局结构树</el-divider> | ||
| 473 | + <el-tree | ||
| 474 | + :data="[activeData]" | ||
| 475 | + :props="layoutTreeProps" | ||
| 476 | + node-key="renderKey" | ||
| 477 | + default-expand-all | ||
| 478 | + draggable | ||
| 479 | + > | ||
| 480 | + <span slot-scope="{ node, data }"> | ||
| 481 | + <span class="node-label"> | ||
| 482 | + <svg-icon class="node-icon" :icon-class="data.tagIcon" /> | ||
| 483 | + {{ node.label }} | ||
| 484 | + </span> | ||
| 485 | + </span> | ||
| 486 | + </el-tree> | ||
| 487 | + </template> | ||
| 488 | + | ||
| 489 | + <template v-if="activeData.layout === 'colFormItem'"> | ||
| 490 | + <el-divider>正则校验</el-divider> | ||
| 491 | + <div | ||
| 492 | + v-for="(item, index) in activeData.regList" | ||
| 493 | + :key="index" | ||
| 494 | + class="reg-item" | ||
| 495 | + > | ||
| 496 | + <span class="close-btn" @click="activeData.regList.splice(index, 1)"> | ||
| 497 | + <i class="el-icon-close" /> | ||
| 498 | + </span> | ||
| 499 | + <el-form-item label="表达式"> | ||
| 500 | + <el-input v-model="item.pattern" placeholder="请输入正则" /> | ||
| 501 | + </el-form-item> | ||
| 502 | + <el-form-item label="错误提示" style="margin-bottom:0"> | ||
| 503 | + <el-input v-model="item.message" placeholder="请输入错误提示" /> | ||
| 504 | + </el-form-item> | ||
| 505 | + </div> | ||
| 506 | + <div style="margin-left: 20px"> | ||
| 507 | + <el-button icon="el-icon-circle-plus-outline" type="text" @click="addReg"> | ||
| 508 | + 添加规则 | ||
| 509 | + </el-button> | ||
| 510 | + </div> | ||
| 511 | + </template> | ||
| 512 | + </el-form> | ||
| 513 | + <!-- 表单属性 --> | ||
| 514 | + <el-form v-show="currentTab === 'form'" size="small" label-width="90px"> | ||
| 515 | + <el-form-item label="表单名"> | ||
| 516 | + <el-input v-model="formConf.formRef" placeholder="请输入表单名(ref)" /> | ||
| 517 | + </el-form-item> | ||
| 518 | + <el-form-item label="表单模型"> | ||
| 519 | + <el-input v-model="formConf.formModel" placeholder="请输入数据模型" /> | ||
| 520 | + </el-form-item> | ||
| 521 | + <el-form-item label="校验模型"> | ||
| 522 | + <el-input v-model="formConf.formRules" placeholder="请输入校验模型" /> | ||
| 523 | + </el-form-item> | ||
| 524 | + <el-form-item label="表单尺寸"> | ||
| 525 | + <el-radio-group v-model="formConf.size"> | ||
| 526 | + <el-radio-button label="medium"> | ||
| 527 | + 中等 | ||
| 528 | + </el-radio-button> | ||
| 529 | + <el-radio-button label="small"> | ||
| 530 | + 较小 | ||
| 531 | + </el-radio-button> | ||
| 532 | + <el-radio-button label="mini"> | ||
| 533 | + 迷你 | ||
| 534 | + </el-radio-button> | ||
| 535 | + </el-radio-group> | ||
| 536 | + </el-form-item> | ||
| 537 | + <el-form-item label="标签对齐"> | ||
| 538 | + <el-radio-group v-model="formConf.labelPosition"> | ||
| 539 | + <el-radio-button label="left"> | ||
| 540 | + 左对齐 | ||
| 541 | + </el-radio-button> | ||
| 542 | + <el-radio-button label="right"> | ||
| 543 | + 右对齐 | ||
| 544 | + </el-radio-button> | ||
| 545 | + <el-radio-button label="top"> | ||
| 546 | + 顶部对齐 | ||
| 547 | + </el-radio-button> | ||
| 548 | + </el-radio-group> | ||
| 549 | + </el-form-item> | ||
| 550 | + <el-form-item label="标签宽度"> | ||
| 551 | + <el-input-number v-model="formConf.labelWidth" placeholder="标签宽度" /> | ||
| 552 | + </el-form-item> | ||
| 553 | + <el-form-item label="栅格间隔"> | ||
| 554 | + <el-input-number v-model="formConf.gutter" :min="0" placeholder="栅格间隔" /> | ||
| 555 | + </el-form-item> | ||
| 556 | + <el-form-item label="禁用表单"> | ||
| 557 | + <el-switch v-model="formConf.disabled" /> | ||
| 558 | + </el-form-item> | ||
| 559 | + <el-form-item label="表单按钮"> | ||
| 560 | + <el-switch v-model="formConf.formBtns" /> | ||
| 561 | + </el-form-item> | ||
| 562 | + <el-form-item label="显示未选中组件边框"> | ||
| 563 | + <el-switch v-model="formConf.unFocusedComponentBorder" /> | ||
| 564 | + </el-form-item> | ||
| 565 | + </el-form> | ||
| 566 | + </el-scrollbar> | ||
| 567 | + </div> | ||
| 568 | + | ||
| 569 | + <treeNode-dialog :visible.sync="dialogVisible" title="添加选项" @commit="addNode" /> | ||
| 570 | + <icons-dialog :visible.sync="iconsVisible" :current="activeData[currentIconModel]" @select="setIcon" /> | ||
| 571 | + </div> | ||
| 572 | +</template> | ||
| 573 | + | ||
| 574 | +<script> | ||
| 575 | +import { isArray } from 'util' | ||
| 576 | +import TreeNodeDialog from './TreeNodeDialog' | ||
| 577 | +import { isNumberStr } from '@/utils/index' | ||
| 578 | +import IconsDialog from './IconsDialog' | ||
| 579 | +import { | ||
| 580 | + inputComponents, | ||
| 581 | + selectComponents, | ||
| 582 | + layoutComponents | ||
| 583 | +} from '@/utils/generator/config' | ||
| 584 | + | ||
| 585 | +const dateTimeFormat = { | ||
| 586 | + date: 'yyyy-MM-dd', | ||
| 587 | + week: 'yyyy 第 WW 周', | ||
| 588 | + month: 'yyyy-MM', | ||
| 589 | + year: 'yyyy', | ||
| 590 | + datetime: 'yyyy-MM-dd HH:mm:ss', | ||
| 591 | + daterange: 'yyyy-MM-dd', | ||
| 592 | + monthrange: 'yyyy-MM', | ||
| 593 | + datetimerange: 'yyyy-MM-dd HH:mm:ss' | ||
| 594 | +} | ||
| 595 | + | ||
| 596 | +export default { | ||
| 597 | + components: { | ||
| 598 | + TreeNodeDialog, | ||
| 599 | + IconsDialog | ||
| 600 | + }, | ||
| 601 | + props: ['showField', 'activeData', 'formConf'], | ||
| 602 | + data() { | ||
| 603 | + return { | ||
| 604 | + currentTab: 'field', | ||
| 605 | + currentNode: null, | ||
| 606 | + dialogVisible: false, | ||
| 607 | + iconsVisible: false, | ||
| 608 | + currentIconModel: null, | ||
| 609 | + dateTypeOptions: [ | ||
| 610 | + { | ||
| 611 | + label: '日(date)', | ||
| 612 | + value: 'date' | ||
| 613 | + }, | ||
| 614 | + { | ||
| 615 | + label: '周(week)', | ||
| 616 | + value: 'week' | ||
| 617 | + }, | ||
| 618 | + { | ||
| 619 | + label: '月(month)', | ||
| 620 | + value: 'month' | ||
| 621 | + }, | ||
| 622 | + { | ||
| 623 | + label: '年(year)', | ||
| 624 | + value: 'year' | ||
| 625 | + }, | ||
| 626 | + { | ||
| 627 | + label: '日期时间(datetime)', | ||
| 628 | + value: 'datetime' | ||
| 629 | + } | ||
| 630 | + ], | ||
| 631 | + dateRangeTypeOptions: [ | ||
| 632 | + { | ||
| 633 | + label: '日期范围(daterange)', | ||
| 634 | + value: 'daterange' | ||
| 635 | + }, | ||
| 636 | + { | ||
| 637 | + label: '月范围(monthrange)', | ||
| 638 | + value: 'monthrange' | ||
| 639 | + }, | ||
| 640 | + { | ||
| 641 | + label: '日期时间范围(datetimerange)', | ||
| 642 | + value: 'datetimerange' | ||
| 643 | + } | ||
| 644 | + ], | ||
| 645 | + colorFormatOptions: [ | ||
| 646 | + { | ||
| 647 | + label: 'hex', | ||
| 648 | + value: 'hex' | ||
| 649 | + }, | ||
| 650 | + { | ||
| 651 | + label: 'rgb', | ||
| 652 | + value: 'rgb' | ||
| 653 | + }, | ||
| 654 | + { | ||
| 655 | + label: 'rgba', | ||
| 656 | + value: 'rgba' | ||
| 657 | + }, | ||
| 658 | + { | ||
| 659 | + label: 'hsv', | ||
| 660 | + value: 'hsv' | ||
| 661 | + }, | ||
| 662 | + { | ||
| 663 | + label: 'hsl', | ||
| 664 | + value: 'hsl' | ||
| 665 | + } | ||
| 666 | + ], | ||
| 667 | + justifyOptions: [ | ||
| 668 | + { | ||
| 669 | + label: 'start', | ||
| 670 | + value: 'start' | ||
| 671 | + }, | ||
| 672 | + { | ||
| 673 | + label: 'end', | ||
| 674 | + value: 'end' | ||
| 675 | + }, | ||
| 676 | + { | ||
| 677 | + label: 'center', | ||
| 678 | + value: 'center' | ||
| 679 | + }, | ||
| 680 | + { | ||
| 681 | + label: 'space-around', | ||
| 682 | + value: 'space-around' | ||
| 683 | + }, | ||
| 684 | + { | ||
| 685 | + label: 'space-between', | ||
| 686 | + value: 'space-between' | ||
| 687 | + } | ||
| 688 | + ], | ||
| 689 | + layoutTreeProps: { | ||
| 690 | + label(data, node) { | ||
| 691 | + return data.componentName || `${data.label}: ${data.vModel}` | ||
| 692 | + } | ||
| 693 | + } | ||
| 694 | + } | ||
| 695 | + }, | ||
| 696 | + computed: { | ||
| 697 | + documentLink() { | ||
| 698 | + return ( | ||
| 699 | + this.activeData.document | ||
| 700 | + || 'https://element.eleme.cn/#/zh-CN/component/installation' | ||
| 701 | + ) | ||
| 702 | + }, | ||
| 703 | + dateOptions() { | ||
| 704 | + if ( | ||
| 705 | + this.activeData.type !== undefined | ||
| 706 | + && this.activeData.tag === 'el-date-picker' | ||
| 707 | + ) { | ||
| 708 | + if (this.activeData['start-placeholder'] === undefined) { | ||
| 709 | + return this.dateTypeOptions | ||
| 710 | + } | ||
| 711 | + return this.dateRangeTypeOptions | ||
| 712 | + } | ||
| 713 | + return [] | ||
| 714 | + }, | ||
| 715 | + tagList() { | ||
| 716 | + return [ | ||
| 717 | + { | ||
| 718 | + label: '输入型组件', | ||
| 719 | + options: inputComponents | ||
| 720 | + }, | ||
| 721 | + { | ||
| 722 | + label: '选择型组件', | ||
| 723 | + options: selectComponents | ||
| 724 | + } | ||
| 725 | + ] | ||
| 726 | + } | ||
| 727 | + }, | ||
| 728 | + methods: { | ||
| 729 | + addReg() { | ||
| 730 | + this.activeData.regList.push({ | ||
| 731 | + pattern: '', | ||
| 732 | + message: '' | ||
| 733 | + }) | ||
| 734 | + }, | ||
| 735 | + addSelectItem() { | ||
| 736 | + this.activeData.options.push({ | ||
| 737 | + label: '', | ||
| 738 | + value: '' | ||
| 739 | + }) | ||
| 740 | + }, | ||
| 741 | + addTreeItem() { | ||
| 742 | + ++this.idGlobal | ||
| 743 | + this.dialogVisible = true | ||
| 744 | + this.currentNode = this.activeData.options | ||
| 745 | + }, | ||
| 746 | + renderContent(h, { node, data, store }) { | ||
| 747 | + return ( | ||
| 748 | + <div class="custom-tree-node"> | ||
| 749 | + <span>{node.label}</span> | ||
| 750 | + <span class="node-operation"> | ||
| 751 | + <i on-click={() => this.append(data)} | ||
| 752 | + class="el-icon-plus" | ||
| 753 | + title="添加" | ||
| 754 | + ></i> | ||
| 755 | + <i on-click={() => this.remove(node, data)} | ||
| 756 | + class="el-icon-delete" | ||
| 757 | + title="删除" | ||
| 758 | + ></i> | ||
| 759 | + </span> | ||
| 760 | + </div> | ||
| 761 | + ) | ||
| 762 | + }, | ||
| 763 | + append(data) { | ||
| 764 | + if (!data.children) { | ||
| 765 | + this.$set(data, 'children', []) | ||
| 766 | + } | ||
| 767 | + this.dialogVisible = true | ||
| 768 | + this.currentNode = data.children | ||
| 769 | + }, | ||
| 770 | + remove(node, data) { | ||
| 771 | + const { parent } = node | ||
| 772 | + const children = parent.data.children || parent.data | ||
| 773 | + const index = children.findIndex(d => d.id === data.id) | ||
| 774 | + children.splice(index, 1) | ||
| 775 | + }, | ||
| 776 | + addNode(data) { | ||
| 777 | + this.currentNode.push(data) | ||
| 778 | + }, | ||
| 779 | + setOptionValue(item, val) { | ||
| 780 | + item.value = isNumberStr(val) ? +val : val | ||
| 781 | + }, | ||
| 782 | + setDefaultValue(val) { | ||
| 783 | + if (Array.isArray(val)) { | ||
| 784 | + return val.join(',') | ||
| 785 | + } | ||
| 786 | + if (['string', 'number'].indexOf(val) > -1) { | ||
| 787 | + return val | ||
| 788 | + } | ||
| 789 | + if (typeof val === 'boolean') { | ||
| 790 | + return `${val}` | ||
| 791 | + } | ||
| 792 | + return val | ||
| 793 | + }, | ||
| 794 | + onDefaultValueInput(str) { | ||
| 795 | + if (isArray(this.activeData.defaultValue)) { | ||
| 796 | + // 数组 | ||
| 797 | + this.$set( | ||
| 798 | + this.activeData, | ||
| 799 | + 'defaultValue', | ||
| 800 | + str.split(',').map(val => (isNumberStr(val) ? +val : val)) | ||
| 801 | + ) | ||
| 802 | + } else if (['true', 'false'].indexOf(str) > -1) { | ||
| 803 | + // 布尔 | ||
| 804 | + this.$set(this.activeData, 'defaultValue', JSON.parse(str)) | ||
| 805 | + } else { | ||
| 806 | + // 字符串和数字 | ||
| 807 | + this.$set( | ||
| 808 | + this.activeData, | ||
| 809 | + 'defaultValue', | ||
| 810 | + isNumberStr(str) ? +str : str | ||
| 811 | + ) | ||
| 812 | + } | ||
| 813 | + }, | ||
| 814 | + onSwitchValueInput(val, name) { | ||
| 815 | + if (['true', 'false'].indexOf(val) > -1) { | ||
| 816 | + this.$set(this.activeData, name, JSON.parse(val)) | ||
| 817 | + } else { | ||
| 818 | + this.$set(this.activeData, name, isNumberStr(val) ? +val : val) | ||
| 819 | + } | ||
| 820 | + }, | ||
| 821 | + setTimeValue(val, type) { | ||
| 822 | + const valueFormat = type === 'week' ? dateTimeFormat.date : val | ||
| 823 | + this.$set(this.activeData, 'defaultValue', null) | ||
| 824 | + this.$set(this.activeData, 'value-format', valueFormat) | ||
| 825 | + this.$set(this.activeData, 'format', val) | ||
| 826 | + }, | ||
| 827 | + spanChange(val) { | ||
| 828 | + this.formConf.span = val | ||
| 829 | + }, | ||
| 830 | + multipleChange(val) { | ||
| 831 | + this.$set(this.activeData, 'defaultValue', val ? [] : '') | ||
| 832 | + }, | ||
| 833 | + dateTypeChange(val) { | ||
| 834 | + this.setTimeValue(dateTimeFormat[val], val) | ||
| 835 | + }, | ||
| 836 | + rangeChange(val) { | ||
| 837 | + this.$set( | ||
| 838 | + this.activeData, | ||
| 839 | + 'defaultValue', | ||
| 840 | + val ? [this.activeData.min, this.activeData.max] : this.activeData.min | ||
| 841 | + ) | ||
| 842 | + }, | ||
| 843 | + rateTextChange(val) { | ||
| 844 | + if (val) this.activeData['show-score'] = false | ||
| 845 | + }, | ||
| 846 | + rateScoreChange(val) { | ||
| 847 | + if (val) this.activeData['show-text'] = false | ||
| 848 | + }, | ||
| 849 | + colorFormatChange(val) { | ||
| 850 | + this.activeData.defaultValue = null | ||
| 851 | + this.activeData['show-alpha'] = val.indexOf('a') > -1 | ||
| 852 | + this.activeData.renderKey = +new Date() // 更新renderKey,重新渲染该组件 | ||
| 853 | + }, | ||
| 854 | + openIconsDialog(model) { | ||
| 855 | + this.iconsVisible = true | ||
| 856 | + this.currentIconModel = model | ||
| 857 | + }, | ||
| 858 | + setIcon(val) { | ||
| 859 | + this.activeData[this.currentIconModel] = val | ||
| 860 | + }, | ||
| 861 | + tagChange(tagIcon) { | ||
| 862 | + let target = inputComponents.find(item => item.tagIcon === tagIcon) | ||
| 863 | + if (!target) target = selectComponents.find(item => item.tagIcon === tagIcon) | ||
| 864 | + this.$emit('tag-change', target) | ||
| 865 | + } | ||
| 866 | + } | ||
| 867 | +} | ||
| 868 | +</script> | ||
| 869 | + | ||
| 870 | +<style lang="scss" scoped> | ||
| 871 | +.right-board { | ||
| 872 | + width: 350px; | ||
| 873 | + position: absolute; | ||
| 874 | + right: 0; | ||
| 875 | + top: 0; | ||
| 876 | + padding-top: 3px; | ||
| 877 | + .field-box { | ||
| 878 | + position: relative; | ||
| 879 | + height: calc(100vh - 42px); | ||
| 880 | + box-sizing: border-box; | ||
| 881 | + overflow: hidden; | ||
| 882 | + } | ||
| 883 | + .el-scrollbar { | ||
| 884 | + height: 100%; | ||
| 885 | + } | ||
| 886 | +} | ||
| 887 | +.select-item { | ||
| 888 | + display: flex; | ||
| 889 | + border: 1px dashed #fff; | ||
| 890 | + box-sizing: border-box; | ||
| 891 | + & .close-btn { | ||
| 892 | + cursor: pointer; | ||
| 893 | + color: #f56c6c; | ||
| 894 | + } | ||
| 895 | + & .el-input + .el-input { | ||
| 896 | + margin-left: 4px; | ||
| 897 | + } | ||
| 898 | +} | ||
| 899 | +.select-item + .select-item { | ||
| 900 | + margin-top: 4px; | ||
| 901 | +} | ||
| 902 | +.select-item.sortable-chosen { | ||
| 903 | + border: 1px dashed #409eff; | ||
| 904 | +} | ||
| 905 | +.select-line-icon { | ||
| 906 | + line-height: 32px; | ||
| 907 | + font-size: 22px; | ||
| 908 | + padding: 0 4px; | ||
| 909 | + color: #777; | ||
| 910 | +} | ||
| 911 | +.option-drag { | ||
| 912 | + cursor: move; | ||
| 913 | +} | ||
| 914 | +.time-range { | ||
| 915 | + .el-date-editor { | ||
| 916 | + width: 227px; | ||
| 917 | + } | ||
| 918 | + ::v-deep .el-icon-time { | ||
| 919 | + display: none; | ||
| 920 | + } | ||
| 921 | +} | ||
| 922 | +.document-link { | ||
| 923 | + position: absolute; | ||
| 924 | + display: block; | ||
| 925 | + width: 26px; | ||
| 926 | + height: 26px; | ||
| 927 | + top: 0; | ||
| 928 | + left: 0; | ||
| 929 | + cursor: pointer; | ||
| 930 | + background: #409eff; | ||
| 931 | + z-index: 1; | ||
| 932 | + border-radius: 0 0 6px 0; | ||
| 933 | + text-align: center; | ||
| 934 | + line-height: 26px; | ||
| 935 | + color: #fff; | ||
| 936 | + font-size: 18px; | ||
| 937 | +} | ||
| 938 | +.node-label{ | ||
| 939 | + font-size: 14px; | ||
| 940 | +} | ||
| 941 | +.node-icon{ | ||
| 942 | + color: #bebfc3; | ||
| 943 | +} | ||
| 944 | +</style> |
yudao-admin-ui/src/views/bpm/form/build/TreeNodeDialog.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <el-dialog | ||
| 4 | + v-bind="$attrs" | ||
| 5 | + :close-on-click-modal="false" | ||
| 6 | + :modal-append-to-body="false" | ||
| 7 | + v-on="$listeners" | ||
| 8 | + @open="onOpen" | ||
| 9 | + @close="onClose" | ||
| 10 | + > | ||
| 11 | + <el-row :gutter="0"> | ||
| 12 | + <el-form | ||
| 13 | + ref="elForm" | ||
| 14 | + :model="formData" | ||
| 15 | + :rules="rules" | ||
| 16 | + size="small" | ||
| 17 | + label-width="100px" | ||
| 18 | + > | ||
| 19 | + <el-col :span="24"> | ||
| 20 | + <el-form-item | ||
| 21 | + label="选项名" | ||
| 22 | + prop="label" | ||
| 23 | + > | ||
| 24 | + <el-input | ||
| 25 | + v-model="formData.label" | ||
| 26 | + placeholder="请输入选项名" | ||
| 27 | + clearable | ||
| 28 | + /> | ||
| 29 | + </el-form-item> | ||
| 30 | + </el-col> | ||
| 31 | + <el-col :span="24"> | ||
| 32 | + <el-form-item | ||
| 33 | + label="选项值" | ||
| 34 | + prop="value" | ||
| 35 | + > | ||
| 36 | + <el-input | ||
| 37 | + v-model="formData.value" | ||
| 38 | + placeholder="请输入选项值" | ||
| 39 | + clearable | ||
| 40 | + > | ||
| 41 | + <el-select | ||
| 42 | + slot="append" | ||
| 43 | + v-model="dataType" | ||
| 44 | + :style="{width: '100px'}" | ||
| 45 | + > | ||
| 46 | + <el-option | ||
| 47 | + v-for="(item, index) in dataTypeOptions" | ||
| 48 | + :key="index" | ||
| 49 | + :label="item.label" | ||
| 50 | + :value="item.value" | ||
| 51 | + :disabled="item.disabled" | ||
| 52 | + /> | ||
| 53 | + </el-select> | ||
| 54 | + </el-input> | ||
| 55 | + </el-form-item> | ||
| 56 | + </el-col> | ||
| 57 | + </el-form> | ||
| 58 | + </el-row> | ||
| 59 | + <div slot="footer"> | ||
| 60 | + <el-button | ||
| 61 | + type="primary" | ||
| 62 | + @click="handelConfirm" | ||
| 63 | + > | ||
| 64 | + 确定 | ||
| 65 | + </el-button> | ||
| 66 | + <el-button @click="close"> | ||
| 67 | + 取消 | ||
| 68 | + </el-button> | ||
| 69 | + </div> | ||
| 70 | + </el-dialog> | ||
| 71 | + </div> | ||
| 72 | +</template> | ||
| 73 | +<script> | ||
| 74 | +import { isNumberStr } from '@/utils/index' | ||
| 75 | + | ||
| 76 | +export default { | ||
| 77 | + components: {}, | ||
| 78 | + inheritAttrs: false, | ||
| 79 | + props: [], | ||
| 80 | + data() { | ||
| 81 | + return { | ||
| 82 | + id: 100, | ||
| 83 | + formData: { | ||
| 84 | + label: undefined, | ||
| 85 | + value: undefined | ||
| 86 | + }, | ||
| 87 | + rules: { | ||
| 88 | + label: [ | ||
| 89 | + { | ||
| 90 | + required: true, | ||
| 91 | + message: '请输入选项名', | ||
| 92 | + trigger: 'blur' | ||
| 93 | + } | ||
| 94 | + ], | ||
| 95 | + value: [ | ||
| 96 | + { | ||
| 97 | + required: true, | ||
| 98 | + message: '请输入选项值', | ||
| 99 | + trigger: 'blur' | ||
| 100 | + } | ||
| 101 | + ] | ||
| 102 | + }, | ||
| 103 | + dataType: 'string', | ||
| 104 | + dataTypeOptions: [ | ||
| 105 | + { | ||
| 106 | + label: '字符串', | ||
| 107 | + value: 'string' | ||
| 108 | + }, | ||
| 109 | + { | ||
| 110 | + label: '数字', | ||
| 111 | + value: 'number' | ||
| 112 | + } | ||
| 113 | + ] | ||
| 114 | + } | ||
| 115 | + }, | ||
| 116 | + computed: {}, | ||
| 117 | + watch: { | ||
| 118 | + // eslint-disable-next-line func-names | ||
| 119 | + 'formData.value': function (val) { | ||
| 120 | + this.dataType = isNumberStr(val) ? 'number' : 'string' | ||
| 121 | + } | ||
| 122 | + }, | ||
| 123 | + created() {}, | ||
| 124 | + mounted() {}, | ||
| 125 | + methods: { | ||
| 126 | + onOpen() { | ||
| 127 | + this.formData = { | ||
| 128 | + label: undefined, | ||
| 129 | + value: undefined | ||
| 130 | + } | ||
| 131 | + }, | ||
| 132 | + onClose() {}, | ||
| 133 | + close() { | ||
| 134 | + this.$emit('update:visible', false) | ||
| 135 | + }, | ||
| 136 | + handelConfirm() { | ||
| 137 | + this.$refs.elForm.validate(valid => { | ||
| 138 | + if (!valid) return | ||
| 139 | + if (this.dataType === 'number') { | ||
| 140 | + this.formData.value = parseFloat(this.formData.value) | ||
| 141 | + } | ||
| 142 | + this.formData.id = this.id++ | ||
| 143 | + this.$emit('commit', this.formData) | ||
| 144 | + this.close() | ||
| 145 | + }) | ||
| 146 | + } | ||
| 147 | + } | ||
| 148 | +} | ||
| 149 | +</script> |
yudao-admin-ui/src/views/bpm/form/build/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="container"> | ||
| 3 | + <div class="left-board"> | ||
| 4 | + <div class="logo-wrapper"> | ||
| 5 | + <div class="logo"> | ||
| 6 | + <img :src="logo" alt="logo"> Form Generator | ||
| 7 | + </div> | ||
| 8 | + </div> | ||
| 9 | + <el-scrollbar class="left-scrollbar"> | ||
| 10 | + <div class="components-list"> | ||
| 11 | + <div class="components-title"> | ||
| 12 | + <svg-icon icon-class="component" />输入型组件 | ||
| 13 | + </div> | ||
| 14 | + <draggable | ||
| 15 | + class="components-draggable" | ||
| 16 | + :list="inputComponents" | ||
| 17 | + :group="{ name: 'componentsGroup', pull: 'clone', put: false }" | ||
| 18 | + :clone="cloneComponent" | ||
| 19 | + draggable=".components-item" | ||
| 20 | + :sort="false" | ||
| 21 | + @end="onEnd" | ||
| 22 | + > | ||
| 23 | + <div | ||
| 24 | + v-for="(element, index) in inputComponents" :key="index" class="components-item" | ||
| 25 | + @click="addComponent(element)" | ||
| 26 | + > | ||
| 27 | + <div class="components-body"> | ||
| 28 | + <svg-icon :icon-class="element.tagIcon" /> | ||
| 29 | + {{ element.label }} | ||
| 30 | + </div> | ||
| 31 | + </div> | ||
| 32 | + </draggable> | ||
| 33 | + <div class="components-title"> | ||
| 34 | + <svg-icon icon-class="component" />选择型组件 | ||
| 35 | + </div> | ||
| 36 | + <draggable | ||
| 37 | + class="components-draggable" | ||
| 38 | + :list="selectComponents" | ||
| 39 | + :group="{ name: 'componentsGroup', pull: 'clone', put: false }" | ||
| 40 | + :clone="cloneComponent" | ||
| 41 | + draggable=".components-item" | ||
| 42 | + :sort="false" | ||
| 43 | + @end="onEnd" | ||
| 44 | + > | ||
| 45 | + <div | ||
| 46 | + v-for="(element, index) in selectComponents" | ||
| 47 | + :key="index" | ||
| 48 | + class="components-item" | ||
| 49 | + @click="addComponent(element)" | ||
| 50 | + > | ||
| 51 | + <div class="components-body"> | ||
| 52 | + <svg-icon :icon-class="element.tagIcon" /> | ||
| 53 | + {{ element.label }} | ||
| 54 | + </div> | ||
| 55 | + </div> | ||
| 56 | + </draggable> | ||
| 57 | + <div class="components-title"> | ||
| 58 | + <svg-icon icon-class="component" /> 布局型组件 | ||
| 59 | + </div> | ||
| 60 | + <draggable | ||
| 61 | + class="components-draggable" :list="layoutComponents" | ||
| 62 | + :group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent" | ||
| 63 | + draggable=".components-item" :sort="false" @end="onEnd" | ||
| 64 | + > | ||
| 65 | + <div | ||
| 66 | + v-for="(element, index) in layoutComponents" :key="index" class="components-item" | ||
| 67 | + @click="addComponent(element)" | ||
| 68 | + > | ||
| 69 | + <div class="components-body"> | ||
| 70 | + <svg-icon :icon-class="element.tagIcon" /> | ||
| 71 | + {{ element.label }} | ||
| 72 | + </div> | ||
| 73 | + </div> | ||
| 74 | + </draggable> | ||
| 75 | + </div> | ||
| 76 | + </el-scrollbar> | ||
| 77 | + </div> | ||
| 78 | + | ||
| 79 | + <div class="center-board"> | ||
| 80 | + <div class="action-bar"> | ||
| 81 | + <el-button icon="el-icon-download" type="text" @click="download"> | ||
| 82 | + 导出vue文件 | ||
| 83 | + </el-button> | ||
| 84 | + <el-button class="copy-btn-main" icon="el-icon-document-copy" type="text" @click="copy"> | ||
| 85 | + 复制代码 | ||
| 86 | + </el-button> | ||
| 87 | + <el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty"> | ||
| 88 | + 清空 | ||
| 89 | + </el-button> | ||
| 90 | + </div> | ||
| 91 | + <el-scrollbar class="center-scrollbar"> | ||
| 92 | + <el-row class="center-board-row" :gutter="formConf.gutter"> | ||
| 93 | + <el-form | ||
| 94 | + :size="formConf.size" | ||
| 95 | + :label-position="formConf.labelPosition" | ||
| 96 | + :disabled="formConf.disabled" | ||
| 97 | + :label-width="formConf.labelWidth + 'px'" | ||
| 98 | + > | ||
| 99 | + <draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup"> | ||
| 100 | + <draggable-item | ||
| 101 | + v-for="(element, index) in drawingList" | ||
| 102 | + :key="element.renderKey" | ||
| 103 | + :drawing-list="drawingList" | ||
| 104 | + :element="element" | ||
| 105 | + :index="index" | ||
| 106 | + :active-id="activeId" | ||
| 107 | + :form-conf="formConf" | ||
| 108 | + @activeItem="activeFormItem" | ||
| 109 | + @copyItem="drawingItemCopy" | ||
| 110 | + @deleteItem="drawingItemDelete" | ||
| 111 | + /> | ||
| 112 | + </draggable> | ||
| 113 | + <div v-show="!drawingList.length" class="empty-info"> | ||
| 114 | + 从左侧拖入或点选组件进行表单设计 | ||
| 115 | + </div> | ||
| 116 | + </el-form> | ||
| 117 | + </el-row> | ||
| 118 | + </el-scrollbar> | ||
| 119 | + </div> | ||
| 120 | + | ||
| 121 | + <right-panel | ||
| 122 | + :active-data="activeData" | ||
| 123 | + :form-conf="formConf" | ||
| 124 | + :show-field="!!drawingList.length" | ||
| 125 | + @tag-change="tagChange" | ||
| 126 | + /> | ||
| 127 | + | ||
| 128 | + <code-type-dialog | ||
| 129 | + :visible.sync="dialogVisible" | ||
| 130 | + title="选择生成类型" | ||
| 131 | + :show-file-name="showFileName" | ||
| 132 | + @confirm="generate" | ||
| 133 | + /> | ||
| 134 | + <input id="copyNode" type="hidden"> | ||
| 135 | + </div> | ||
| 136 | +</template> | ||
| 137 | + | ||
| 138 | +<script> | ||
| 139 | +import draggable from 'vuedraggable' | ||
| 140 | +import { saveAs } from 'file-saver' | ||
| 141 | +import beautifier from 'js-beautify' | ||
| 142 | +import ClipboardJS from 'clipboard' | ||
| 143 | +import render from '@/utils/generator/render' | ||
| 144 | +import RightPanel from './RightPanel' | ||
| 145 | +import { | ||
| 146 | + inputComponents, | ||
| 147 | + selectComponents, | ||
| 148 | + layoutComponents, | ||
| 149 | + formConf | ||
| 150 | +} from '@/utils/generator/config' | ||
| 151 | +import { | ||
| 152 | + exportDefault, beautifierConf, isNumberStr, titleCase | ||
| 153 | +} from '@/utils/index' | ||
| 154 | +import { | ||
| 155 | + makeUpHtml, vueTemplate, vueScript, cssStyle | ||
| 156 | +} from '@/utils/generator/html' | ||
| 157 | +import { makeUpJs } from '@/utils/generator/js' | ||
| 158 | +import { makeUpCss } from '@/utils/generator/css' | ||
| 159 | +import drawingDefalut from '@/utils/generator/drawingDefalut' | ||
| 160 | +import logo from '@/assets/logo/logo.png' | ||
| 161 | +import CodeTypeDialog from './CodeTypeDialog' | ||
| 162 | +import DraggableItem from './DraggableItem' | ||
| 163 | + | ||
| 164 | +const emptyActiveData = { style: {}, autosize: {} } | ||
| 165 | +let oldActiveId | ||
| 166 | +let tempActiveData | ||
| 167 | + | ||
| 168 | +export default { | ||
| 169 | + components: { | ||
| 170 | + draggable, | ||
| 171 | + render, | ||
| 172 | + RightPanel, | ||
| 173 | + CodeTypeDialog, | ||
| 174 | + DraggableItem | ||
| 175 | + }, | ||
| 176 | + data() { | ||
| 177 | + return { | ||
| 178 | + logo, | ||
| 179 | + idGlobal: 100, | ||
| 180 | + formConf, | ||
| 181 | + inputComponents, | ||
| 182 | + selectComponents, | ||
| 183 | + layoutComponents, | ||
| 184 | + labelWidth: 100, | ||
| 185 | + drawingList: drawingDefalut, | ||
| 186 | + drawingData: {}, | ||
| 187 | + activeId: drawingDefalut[0].formId, | ||
| 188 | + drawerVisible: false, | ||
| 189 | + formData: {}, | ||
| 190 | + dialogVisible: false, | ||
| 191 | + generateConf: null, | ||
| 192 | + showFileName: false, | ||
| 193 | + activeData: drawingDefalut[0] | ||
| 194 | + } | ||
| 195 | + }, | ||
| 196 | + computed: { | ||
| 197 | + }, | ||
| 198 | + watch: { | ||
| 199 | + // eslint-disable-next-line func-names | ||
| 200 | + 'activeData.label': function (val, oldVal) { | ||
| 201 | + if ( | ||
| 202 | + this.activeData.placeholder === undefined | ||
| 203 | + || !this.activeData.tag | ||
| 204 | + || oldActiveId !== this.activeId | ||
| 205 | + ) { | ||
| 206 | + return | ||
| 207 | + } | ||
| 208 | + this.activeData.placeholder = this.activeData.placeholder.replace(oldVal, '') + val | ||
| 209 | + }, | ||
| 210 | + activeId: { | ||
| 211 | + handler(val) { | ||
| 212 | + oldActiveId = val | ||
| 213 | + }, | ||
| 214 | + immediate: true | ||
| 215 | + } | ||
| 216 | + }, | ||
| 217 | + mounted() { | ||
| 218 | + const clipboard = new ClipboardJS('#copyNode', { | ||
| 219 | + text: trigger => { | ||
| 220 | + const codeStr = this.generateCode() | ||
| 221 | + this.$notify({ | ||
| 222 | + title: '成功', | ||
| 223 | + message: '代码已复制到剪切板,可粘贴。', | ||
| 224 | + type: 'success' | ||
| 225 | + }) | ||
| 226 | + return codeStr | ||
| 227 | + } | ||
| 228 | + }) | ||
| 229 | + clipboard.on('error', e => { | ||
| 230 | + this.$message.error('代码复制失败') | ||
| 231 | + }) | ||
| 232 | + }, | ||
| 233 | + methods: { | ||
| 234 | + activeFormItem(element) { | ||
| 235 | + this.activeData = element | ||
| 236 | + this.activeId = element.formId | ||
| 237 | + }, | ||
| 238 | + onEnd(obj, a) { | ||
| 239 | + if (obj.from !== obj.to) { | ||
| 240 | + this.activeData = tempActiveData | ||
| 241 | + this.activeId = this.idGlobal | ||
| 242 | + } | ||
| 243 | + }, | ||
| 244 | + addComponent(item) { | ||
| 245 | + const clone = this.cloneComponent(item) | ||
| 246 | + this.drawingList.push(clone) | ||
| 247 | + this.activeFormItem(clone) | ||
| 248 | + }, | ||
| 249 | + cloneComponent(origin) { | ||
| 250 | + const clone = JSON.parse(JSON.stringify(origin)) | ||
| 251 | + clone.formId = ++this.idGlobal | ||
| 252 | + clone.span = formConf.span | ||
| 253 | + clone.renderKey = +new Date() // 改变renderKey后可以实现强制更新组件 | ||
| 254 | + if (!clone.layout) clone.layout = 'colFormItem' | ||
| 255 | + if (clone.layout === 'colFormItem') { | ||
| 256 | + clone.vModel = `field${this.idGlobal}` | ||
| 257 | + clone.placeholder !== undefined && (clone.placeholder += clone.label) | ||
| 258 | + tempActiveData = clone | ||
| 259 | + } else if (clone.layout === 'rowFormItem') { | ||
| 260 | + delete clone.label | ||
| 261 | + clone.componentName = `row${this.idGlobal}` | ||
| 262 | + clone.gutter = this.formConf.gutter | ||
| 263 | + tempActiveData = clone | ||
| 264 | + } | ||
| 265 | + return tempActiveData | ||
| 266 | + }, | ||
| 267 | + AssembleFormData() { | ||
| 268 | + this.formData = { | ||
| 269 | + fields: JSON.parse(JSON.stringify(this.drawingList)), | ||
| 270 | + ...this.formConf | ||
| 271 | + } | ||
| 272 | + }, | ||
| 273 | + generate(data) { | ||
| 274 | + const func = this[`exec${titleCase(this.operationType)}`] | ||
| 275 | + this.generateConf = data | ||
| 276 | + func && func(data) | ||
| 277 | + }, | ||
| 278 | + execRun(data) { | ||
| 279 | + this.AssembleFormData() | ||
| 280 | + this.drawerVisible = true | ||
| 281 | + }, | ||
| 282 | + execDownload(data) { | ||
| 283 | + const codeStr = this.generateCode() | ||
| 284 | + const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' }) | ||
| 285 | + saveAs(blob, data.fileName) | ||
| 286 | + }, | ||
| 287 | + execCopy(data) { | ||
| 288 | + document.getElementById('copyNode').click() | ||
| 289 | + }, | ||
| 290 | + empty() { | ||
| 291 | + this.$confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then( | ||
| 292 | + () => { | ||
| 293 | + this.drawingList = [] | ||
| 294 | + } | ||
| 295 | + ) | ||
| 296 | + }, | ||
| 297 | + drawingItemCopy(item, parent) { | ||
| 298 | + let clone = JSON.parse(JSON.stringify(item)) | ||
| 299 | + clone = this.createIdAndKey(clone) | ||
| 300 | + parent.push(clone) | ||
| 301 | + this.activeFormItem(clone) | ||
| 302 | + }, | ||
| 303 | + createIdAndKey(item) { | ||
| 304 | + item.formId = ++this.idGlobal | ||
| 305 | + item.renderKey = +new Date() | ||
| 306 | + if (item.layout === 'colFormItem') { | ||
| 307 | + item.vModel = `field${this.idGlobal}` | ||
| 308 | + } else if (item.layout === 'rowFormItem') { | ||
| 309 | + item.componentName = `row${this.idGlobal}` | ||
| 310 | + } | ||
| 311 | + if (Array.isArray(item.children)) { | ||
| 312 | + item.children = item.children.map(childItem => this.createIdAndKey(childItem)) | ||
| 313 | + } | ||
| 314 | + return item | ||
| 315 | + }, | ||
| 316 | + drawingItemDelete(index, parent) { | ||
| 317 | + parent.splice(index, 1) | ||
| 318 | + this.$nextTick(() => { | ||
| 319 | + const len = this.drawingList.length | ||
| 320 | + if (len) { | ||
| 321 | + this.activeFormItem(this.drawingList[len - 1]) | ||
| 322 | + } | ||
| 323 | + }) | ||
| 324 | + }, | ||
| 325 | + generateCode() { | ||
| 326 | + const { type } = this.generateConf | ||
| 327 | + this.AssembleFormData() | ||
| 328 | + const script = vueScript(makeUpJs(this.formData, type)) | ||
| 329 | + const html = vueTemplate(makeUpHtml(this.formData, type)) | ||
| 330 | + const css = cssStyle(makeUpCss(this.formData)) | ||
| 331 | + return beautifier.html(html + script + css, beautifierConf.html) | ||
| 332 | + }, | ||
| 333 | + download() { | ||
| 334 | + this.dialogVisible = true | ||
| 335 | + this.showFileName = true | ||
| 336 | + this.operationType = 'download' | ||
| 337 | + }, | ||
| 338 | + run() { | ||
| 339 | + this.dialogVisible = true | ||
| 340 | + this.showFileName = false | ||
| 341 | + this.operationType = 'run' | ||
| 342 | + }, | ||
| 343 | + copy() { | ||
| 344 | + this.dialogVisible = true | ||
| 345 | + this.showFileName = false | ||
| 346 | + this.operationType = 'copy' | ||
| 347 | + }, | ||
| 348 | + tagChange(newTag) { | ||
| 349 | + newTag = this.cloneComponent(newTag) | ||
| 350 | + newTag.vModel = this.activeData.vModel | ||
| 351 | + newTag.formId = this.activeId | ||
| 352 | + newTag.span = this.activeData.span | ||
| 353 | + delete this.activeData.tag | ||
| 354 | + delete this.activeData.tagIcon | ||
| 355 | + delete this.activeData.document | ||
| 356 | + Object.keys(newTag).forEach(key => { | ||
| 357 | + if (this.activeData[key] !== undefined | ||
| 358 | + && typeof this.activeData[key] === typeof newTag[key]) { | ||
| 359 | + newTag[key] = this.activeData[key] | ||
| 360 | + } | ||
| 361 | + }) | ||
| 362 | + this.activeData = newTag | ||
| 363 | + this.updateDrawingList(newTag, this.drawingList) | ||
| 364 | + }, | ||
| 365 | + updateDrawingList(newTag, list) { | ||
| 366 | + const index = list.findIndex(item => item.formId === this.activeId) | ||
| 367 | + if (index > -1) { | ||
| 368 | + list.splice(index, 1, newTag) | ||
| 369 | + } else { | ||
| 370 | + list.forEach(item => { | ||
| 371 | + if (Array.isArray(item.children)) this.updateDrawingList(newTag, item.children) | ||
| 372 | + }) | ||
| 373 | + } | ||
| 374 | + } | ||
| 375 | + } | ||
| 376 | +} | ||
| 377 | +</script> | ||
| 378 | + | ||
| 379 | +<style lang='scss'> | ||
| 380 | +body, html{ | ||
| 381 | + margin: 0; | ||
| 382 | + padding: 0; | ||
| 383 | + background: #fff; | ||
| 384 | + -moz-osx-font-smoothing: grayscale; | ||
| 385 | + -webkit-font-smoothing: antialiased; | ||
| 386 | + text-rendering: optimizeLegibility; | ||
| 387 | + font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji; | ||
| 388 | +} | ||
| 389 | + | ||
| 390 | +input, textarea{ | ||
| 391 | + font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji; | ||
| 392 | +} | ||
| 393 | + | ||
| 394 | +.editor-tabs{ | ||
| 395 | + background: #121315; | ||
| 396 | + .el-tabs__header{ | ||
| 397 | + margin: 0; | ||
| 398 | + border-bottom-color: #121315; | ||
| 399 | + .el-tabs__nav{ | ||
| 400 | + border-color: #121315; | ||
| 401 | + } | ||
| 402 | + } | ||
| 403 | + .el-tabs__item{ | ||
| 404 | + height: 32px; | ||
| 405 | + line-height: 32px; | ||
| 406 | + color: #888a8e; | ||
| 407 | + border-left: 1px solid #121315 !important; | ||
| 408 | + background: #363636; | ||
| 409 | + margin-right: 5px; | ||
| 410 | + user-select: none; | ||
| 411 | + } | ||
| 412 | + .el-tabs__item.is-active{ | ||
| 413 | + background: #1e1e1e; | ||
| 414 | + border-bottom-color: #1e1e1e!important; | ||
| 415 | + color: #fff; | ||
| 416 | + } | ||
| 417 | + .el-icon-edit{ | ||
| 418 | + color: #f1fa8c; | ||
| 419 | + } | ||
| 420 | + .el-icon-document{ | ||
| 421 | + color: #a95812; | ||
| 422 | + } | ||
| 423 | +} | ||
| 424 | + | ||
| 425 | +// home | ||
| 426 | +.right-scrollbar { | ||
| 427 | + .el-scrollbar__view { | ||
| 428 | + padding: 12px 18px 15px 15px; | ||
| 429 | + } | ||
| 430 | +} | ||
| 431 | +.left-scrollbar .el-scrollbar__wrap { | ||
| 432 | + box-sizing: border-box; | ||
| 433 | + overflow-x: hidden !important; | ||
| 434 | + margin-bottom: 0 !important; | ||
| 435 | +} | ||
| 436 | +.center-tabs{ | ||
| 437 | + .el-tabs__header{ | ||
| 438 | + margin-bottom: 0!important; | ||
| 439 | + } | ||
| 440 | + .el-tabs__item{ | ||
| 441 | + width: 50%; | ||
| 442 | + text-align: center; | ||
| 443 | + } | ||
| 444 | + .el-tabs__nav{ | ||
| 445 | + width: 100%; | ||
| 446 | + } | ||
| 447 | +} | ||
| 448 | +.reg-item{ | ||
| 449 | + padding: 12px 6px; | ||
| 450 | + background: #f8f8f8; | ||
| 451 | + position: relative; | ||
| 452 | + border-radius: 4px; | ||
| 453 | + .close-btn{ | ||
| 454 | + position: absolute; | ||
| 455 | + right: -6px; | ||
| 456 | + top: -6px; | ||
| 457 | + display: block; | ||
| 458 | + width: 16px; | ||
| 459 | + height: 16px; | ||
| 460 | + line-height: 16px; | ||
| 461 | + background: rgba(0, 0, 0, 0.2); | ||
| 462 | + border-radius: 50%; | ||
| 463 | + color: #fff; | ||
| 464 | + text-align: center; | ||
| 465 | + z-index: 1; | ||
| 466 | + cursor: pointer; | ||
| 467 | + font-size: 12px; | ||
| 468 | + &:hover{ | ||
| 469 | + background: rgba(210, 23, 23, 0.5) | ||
| 470 | + } | ||
| 471 | + } | ||
| 472 | + & + .reg-item{ | ||
| 473 | + margin-top: 18px; | ||
| 474 | + } | ||
| 475 | +} | ||
| 476 | +.action-bar{ | ||
| 477 | + & .el-button+.el-button { | ||
| 478 | + margin-left: 15px; | ||
| 479 | + } | ||
| 480 | + & i { | ||
| 481 | + font-size: 20px; | ||
| 482 | + vertical-align: middle; | ||
| 483 | + position: relative; | ||
| 484 | + top: -1px; | ||
| 485 | + } | ||
| 486 | +} | ||
| 487 | + | ||
| 488 | +.custom-tree-node{ | ||
| 489 | + width: 100%; | ||
| 490 | + font-size: 14px; | ||
| 491 | + .node-operation{ | ||
| 492 | + float: right; | ||
| 493 | + } | ||
| 494 | + i[class*="el-icon"] + i[class*="el-icon"]{ | ||
| 495 | + margin-left: 6px; | ||
| 496 | + } | ||
| 497 | + .el-icon-plus{ | ||
| 498 | + color: #409EFF; | ||
| 499 | + } | ||
| 500 | + .el-icon-delete{ | ||
| 501 | + color: #157a0c; | ||
| 502 | + } | ||
| 503 | +} | ||
| 504 | + | ||
| 505 | +.left-scrollbar .el-scrollbar__view{ | ||
| 506 | + overflow-x: hidden; | ||
| 507 | +} | ||
| 508 | + | ||
| 509 | +.el-rate{ | ||
| 510 | + display: inline-block; | ||
| 511 | + vertical-align: text-top; | ||
| 512 | +} | ||
| 513 | +.el-upload__tip{ | ||
| 514 | + line-height: 1.2; | ||
| 515 | +} | ||
| 516 | + | ||
| 517 | +$selectedColor: #f6f7ff; | ||
| 518 | +$lighterBlue: #409EFF; | ||
| 519 | + | ||
| 520 | +.container { | ||
| 521 | + position: relative; | ||
| 522 | + width: 100%; | ||
| 523 | + height: 100%; | ||
| 524 | +} | ||
| 525 | + | ||
| 526 | +.components-list { | ||
| 527 | + padding: 8px; | ||
| 528 | + box-sizing: border-box; | ||
| 529 | + height: 100%; | ||
| 530 | + .components-item { | ||
| 531 | + display: inline-block; | ||
| 532 | + width: 48%; | ||
| 533 | + margin: 1%; | ||
| 534 | + transition: transform 0ms !important; | ||
| 535 | + } | ||
| 536 | +} | ||
| 537 | +.components-draggable{ | ||
| 538 | + padding-bottom: 20px; | ||
| 539 | +} | ||
| 540 | +.components-title{ | ||
| 541 | + font-size: 14px; | ||
| 542 | + color: #222; | ||
| 543 | + margin: 6px 2px; | ||
| 544 | + .svg-icon{ | ||
| 545 | + color: #666; | ||
| 546 | + font-size: 18px; | ||
| 547 | + } | ||
| 548 | +} | ||
| 549 | + | ||
| 550 | +.components-body { | ||
| 551 | + padding: 8px 10px; | ||
| 552 | + background: $selectedColor; | ||
| 553 | + font-size: 12px; | ||
| 554 | + cursor: move; | ||
| 555 | + border: 1px dashed $selectedColor; | ||
| 556 | + border-radius: 3px; | ||
| 557 | + .svg-icon{ | ||
| 558 | + color: #777; | ||
| 559 | + font-size: 15px; | ||
| 560 | + } | ||
| 561 | + &:hover { | ||
| 562 | + border: 1px dashed #787be8; | ||
| 563 | + color: #787be8; | ||
| 564 | + .svg-icon { | ||
| 565 | + color: #787be8; | ||
| 566 | + } | ||
| 567 | + } | ||
| 568 | +} | ||
| 569 | + | ||
| 570 | +.left-board { | ||
| 571 | + width: 260px; | ||
| 572 | + position: absolute; | ||
| 573 | + left: 0; | ||
| 574 | + top: 0; | ||
| 575 | + height: 100vh; | ||
| 576 | +} | ||
| 577 | +.left-scrollbar{ | ||
| 578 | + height: calc(100vh - 42px); | ||
| 579 | + overflow: hidden; | ||
| 580 | +} | ||
| 581 | +.center-scrollbar { | ||
| 582 | + height: calc(100vh - 42px); | ||
| 583 | + overflow: hidden; | ||
| 584 | + border-left: 1px solid #f1e8e8; | ||
| 585 | + border-right: 1px solid #f1e8e8; | ||
| 586 | + box-sizing: border-box; | ||
| 587 | +} | ||
| 588 | +.center-board { | ||
| 589 | + height: 100vh; | ||
| 590 | + width: auto; | ||
| 591 | + margin: 0 350px 0 260px; | ||
| 592 | + box-sizing: border-box; | ||
| 593 | +} | ||
| 594 | +.empty-info{ | ||
| 595 | + position: absolute; | ||
| 596 | + top: 46%; | ||
| 597 | + left: 0; | ||
| 598 | + right: 0; | ||
| 599 | + text-align: center; | ||
| 600 | + font-size: 18px; | ||
| 601 | + color: #ccb1ea; | ||
| 602 | + letter-spacing: 4px; | ||
| 603 | +} | ||
| 604 | +.action-bar{ | ||
| 605 | + position: relative; | ||
| 606 | + height: 42px; | ||
| 607 | + text-align: right; | ||
| 608 | + padding: 0 15px; | ||
| 609 | + box-sizing: border-box;; | ||
| 610 | + border: 1px solid #f1e8e8; | ||
| 611 | + border-top: none; | ||
| 612 | + border-left: none; | ||
| 613 | + .delete-btn{ | ||
| 614 | + color: #F56C6C; | ||
| 615 | + } | ||
| 616 | +} | ||
| 617 | +.logo-wrapper{ | ||
| 618 | + position: relative; | ||
| 619 | + height: 42px; | ||
| 620 | + background: #fff; | ||
| 621 | + border-bottom: 1px solid #f1e8e8; | ||
| 622 | + box-sizing: border-box; | ||
| 623 | +} | ||
| 624 | +.logo{ | ||
| 625 | + position: absolute; | ||
| 626 | + left: 12px; | ||
| 627 | + top: 6px; | ||
| 628 | + line-height: 30px; | ||
| 629 | + color: #00afff; | ||
| 630 | + font-weight: 600; | ||
| 631 | + font-size: 17px; | ||
| 632 | + white-space: nowrap; | ||
| 633 | + > img{ | ||
| 634 | + width: 30px; | ||
| 635 | + height: 30px; | ||
| 636 | + vertical-align: top; | ||
| 637 | + } | ||
| 638 | + .github{ | ||
| 639 | + display: inline-block; | ||
| 640 | + vertical-align: sub; | ||
| 641 | + margin-left: 15px; | ||
| 642 | + > img{ | ||
| 643 | + height: 22px; | ||
| 644 | + } | ||
| 645 | + } | ||
| 646 | +} | ||
| 647 | + | ||
| 648 | +.center-board-row { | ||
| 649 | + padding: 12px 12px 15px 12px; | ||
| 650 | + box-sizing: border-box; | ||
| 651 | + & > .el-form { | ||
| 652 | + // 69 = 12+15+42 | ||
| 653 | + height: calc(100vh - 69px); | ||
| 654 | + } | ||
| 655 | +} | ||
| 656 | +.drawing-board { | ||
| 657 | + height: 100%; | ||
| 658 | + position: relative; | ||
| 659 | + .components-body { | ||
| 660 | + padding: 0; | ||
| 661 | + margin: 0; | ||
| 662 | + font-size: 0; | ||
| 663 | + } | ||
| 664 | + .sortable-ghost { | ||
| 665 | + position: relative; | ||
| 666 | + display: block; | ||
| 667 | + overflow: hidden; | ||
| 668 | + &::before { | ||
| 669 | + content: " "; | ||
| 670 | + position: absolute; | ||
| 671 | + left: 0; | ||
| 672 | + right: 0; | ||
| 673 | + top: 0; | ||
| 674 | + height: 3px; | ||
| 675 | + background: rgb(89, 89, 223); | ||
| 676 | + z-index: 2; | ||
| 677 | + } | ||
| 678 | + } | ||
| 679 | + .components-item.sortable-ghost { | ||
| 680 | + width: 100%; | ||
| 681 | + height: 60px; | ||
| 682 | + background-color: $selectedColor; | ||
| 683 | + } | ||
| 684 | + .active-from-item { | ||
| 685 | + & > .el-form-item{ | ||
| 686 | + background: $selectedColor; | ||
| 687 | + border-radius: 6px; | ||
| 688 | + } | ||
| 689 | + & > .drawing-item-copy, & > .drawing-item-delete{ | ||
| 690 | + display: initial; | ||
| 691 | + } | ||
| 692 | + & > .component-name{ | ||
| 693 | + color: $lighterBlue; | ||
| 694 | + } | ||
| 695 | + } | ||
| 696 | + .el-form-item{ | ||
| 697 | + margin-bottom: 15px; | ||
| 698 | + } | ||
| 699 | +} | ||
| 700 | +.drawing-item{ | ||
| 701 | + position: relative; | ||
| 702 | + cursor: move; | ||
| 703 | + &.unfocus-bordered:not(.activeFromItem) > div:first-child { | ||
| 704 | + border: 1px dashed #ccc; | ||
| 705 | + } | ||
| 706 | + .el-form-item{ | ||
| 707 | + padding: 12px 10px; | ||
| 708 | + } | ||
| 709 | +} | ||
| 710 | +.drawing-row-item{ | ||
| 711 | + position: relative; | ||
| 712 | + cursor: move; | ||
| 713 | + box-sizing: border-box; | ||
| 714 | + border: 1px dashed #ccc; | ||
| 715 | + border-radius: 3px; | ||
| 716 | + padding: 0 2px; | ||
| 717 | + margin-bottom: 15px; | ||
| 718 | + .drawing-row-item { | ||
| 719 | + margin-bottom: 2px; | ||
| 720 | + } | ||
| 721 | + .el-col{ | ||
| 722 | + margin-top: 22px; | ||
| 723 | + } | ||
| 724 | + .el-form-item{ | ||
| 725 | + margin-bottom: 0; | ||
| 726 | + } | ||
| 727 | + .drag-wrapper{ | ||
| 728 | + min-height: 80px; | ||
| 729 | + } | ||
| 730 | + &.active-from-item{ | ||
| 731 | + border: 1px dashed $lighterBlue; | ||
| 732 | + } | ||
| 733 | + .component-name{ | ||
| 734 | + position: absolute; | ||
| 735 | + top: 0; | ||
| 736 | + left: 0; | ||
| 737 | + font-size: 12px; | ||
| 738 | + color: #bbb; | ||
| 739 | + display: inline-block; | ||
| 740 | + padding: 0 6px; | ||
| 741 | + } | ||
| 742 | +} | ||
| 743 | +.drawing-item, .drawing-row-item{ | ||
| 744 | + &:hover { | ||
| 745 | + & > .el-form-item{ | ||
| 746 | + background: $selectedColor; | ||
| 747 | + border-radius: 6px; | ||
| 748 | + } | ||
| 749 | + & > .drawing-item-copy, & > .drawing-item-delete{ | ||
| 750 | + display: initial; | ||
| 751 | + } | ||
| 752 | + } | ||
| 753 | + & > .drawing-item-copy, & > .drawing-item-delete{ | ||
| 754 | + display: none; | ||
| 755 | + position: absolute; | ||
| 756 | + top: -10px; | ||
| 757 | + width: 22px; | ||
| 758 | + height: 22px; | ||
| 759 | + line-height: 22px; | ||
| 760 | + text-align: center; | ||
| 761 | + border-radius: 50%; | ||
| 762 | + font-size: 12px; | ||
| 763 | + border: 1px solid; | ||
| 764 | + cursor: pointer; | ||
| 765 | + z-index: 1; | ||
| 766 | + } | ||
| 767 | + & > .drawing-item-copy{ | ||
| 768 | + right: 56px; | ||
| 769 | + border-color: $lighterBlue; | ||
| 770 | + color: $lighterBlue; | ||
| 771 | + background: #fff; | ||
| 772 | + &:hover{ | ||
| 773 | + background: $lighterBlue; | ||
| 774 | + color: #fff; | ||
| 775 | + } | ||
| 776 | + } | ||
| 777 | + & > .drawing-item-delete{ | ||
| 778 | + right: 24px; | ||
| 779 | + border-color: #F56C6C; | ||
| 780 | + color: #F56C6C; | ||
| 781 | + background: #fff; | ||
| 782 | + &:hover{ | ||
| 783 | + background: #F56C6C; | ||
| 784 | + color: #fff; | ||
| 785 | + } | ||
| 786 | + } | ||
| 787 | +} | ||
| 788 | + | ||
| 789 | +</style> |