Commit 863ab6f33ae34ab8af47fcdb64e74e75f66d5a95

Authored by YunaiV
1 parent d574a99d

流程表单,接入新的 form generator 版本

yudao-admin-ui/src/components/RADME.md 0 → 100644
  1 +## form-generator
  2 +
  3 +github 地址:https://github.com/JakHuang/form-generator
  4 +
  5 +* generator
  6 +* parser
  7 +* render
  8 +* tinymce
0 \ No newline at end of file 9 \ No newline at end of file
yudao-admin-ui/src/views/bpm/form/formEditor.vue
@@ -7,42 +7,33 @@ @@ -7,42 +7,33 @@
7 <el-scrollbar class="left-scrollbar"> 7 <el-scrollbar class="left-scrollbar">
8 <!-- 左边:表单项 --> 8 <!-- 左边:表单项 -->
9 <div class="components-list"> 9 <div class="components-list">
10 - <div class="components-title">  
11 - <svg-icon icon-class="component" />输入型组件  
12 - </div>  
13 - <draggable class="components-draggable" :list="inputComponents" :group="{ name: 'componentsGroup', pull: 'clone', put: false }"  
14 - :clone="cloneComponent" draggable=".components-item" :sort="false" @end="onEnd">  
15 - <div v-for="(element, index) in inputComponents" :key="index" class="components-item" @click="addComponent(element)">  
16 - <div class="components-body">  
17 - <svg-icon :icon-class="element.tagIcon" />  
18 - {{ element.label }}  
19 - </div> 10 + <div v-for="(item, listIndex) in leftComponents" :key="listIndex">
  11 + <div class="components-title">
  12 + <svg-icon icon-class="component" />
  13 + {{ item.title }}
20 </div> 14 </div>
21 - </draggable>  
22 - <div class="components-title">  
23 - <svg-icon icon-class="component" />选择型组件  
24 - </div>  
25 - <draggable class="components-draggable" :list="selectComponents" :group="{ name: 'componentsGroup', pull: 'clone', put: false }"  
26 - :clone="cloneComponent" draggable=".components-item" :sort="false" @end="onEnd">  
27 - <div v-for="(element, index) in selectComponents" :key="index" class="components-item" @click="addComponent(element)">  
28 - <div class="components-body">  
29 - <svg-icon :icon-class="element.tagIcon" />  
30 - {{ element.label }} 15 + <draggable
  16 + class="components-draggable"
  17 + :list="item.list"
  18 + :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
  19 + :clone="cloneComponent"
  20 + draggable=".components-item"
  21 + :sort="false"
  22 + @end="onEnd"
  23 + >
  24 + <div
  25 + v-for="(element, index) in item.list"
  26 + :key="index"
  27 + class="components-item"
  28 + @click="addComponent(element)"
  29 + >
  30 + <div class="components-body">
  31 + <svg-icon :icon-class="element.__config__.tagIcon" />
  32 + {{ element.__config__.label }}
  33 + </div>
31 </div> 34 </div>
32 - </div>  
33 - </draggable>  
34 - <div class="components-title">  
35 - <svg-icon icon-class="component" />布局型组件 35 + </draggable>
36 </div> 36 </div>
37 - <draggable class="components-draggable" :list="layoutComponents" :group="{ name: 'componentsGroup', pull: 'clone', put: false }"  
38 - :clone="cloneComponent" draggable=".components-item" :sort="false" @end="onEnd">  
39 - <div v-for="(element, index) in layoutComponents" :key="index" class="components-item" @click="addComponent(element)">  
40 - <div class="components-body">  
41 - <svg-icon :icon-class="element.tagIcon" />  
42 - {{ element.label }}  
43 - </div>  
44 - </div>  
45 - </draggable>  
46 37
47 <!-- 左边:动态表单 --> 38 <!-- 左边:动态表单 -->
48 <el-form ref="form" :model="form" :rules="rules" label-width="80px"> 39 <el-form ref="form" :model="form" :rules="rules" label-width="80px">
@@ -64,20 +55,47 @@ @@ -64,20 +55,47 @@
64 </div> 55 </div>
65 56
66 <div class="center-board"> 57 <div class="center-board">
67 - <!-- 上面:操作按钮 -->  
68 <div class="action-bar"> 58 <div class="action-bar">
69 <el-button icon="el-icon-check" type="text" @click="save">保存</el-button> 59 <el-button icon="el-icon-check" type="text" @click="save">保存</el-button>
70 - <el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty">清空</el-button> 60 + <!-- <el-button icon="el-icon-video-play" type="text" @click="run">-->
  61 +<!-- 运行-->
  62 +<!-- </el-button>-->
  63 + <el-button icon="el-icon-view" type="text" @click="showJson">
  64 + 查看json
  65 + </el-button>
  66 +<!-- <el-button icon="el-icon-download" type="text" @click="download">-->
  67 +<!-- 导出vue文件-->
  68 +<!-- </el-button>-->
  69 +<!-- <el-button class="copy-btn-main" icon="el-icon-document-copy" type="text" @click="copy">-->
  70 +<!-- 复制代码-->
  71 +<!-- </el-button>-->
  72 + <el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty">
  73 + 清空
  74 + </el-button>
71 </div> 75 </div>
  76 +
72 <!-- 中间,表单项 --> 77 <!-- 中间,表单项 -->
73 <el-scrollbar class="center-scrollbar"> 78 <el-scrollbar class="center-scrollbar">
74 <el-row class="center-board-row" :gutter="formConf.gutter"> 79 <el-row class="center-board-row" :gutter="formConf.gutter">
75 - <el-form :size="formConf.size" :label-position="formConf.labelPosition" :disabled="formConf.disabled"  
76 - :label-width="formConf.labelWidth + 'px'"> 80 + <el-form
  81 + :size="formConf.size"
  82 + :label-position="formConf.labelPosition"
  83 + :disabled="formConf.disabled"
  84 + :label-width="formConf.labelWidth + 'px'"
  85 + >
77 <draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup"> 86 <draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup">
78 - <draggable-item v-for="(element, index) in drawingList" :key="element.renderKey" :drawing-list="drawingList"  
79 - :element="element" :index="index" :active-id="activeId" :form-conf="formConf"  
80 - @activeItem="activeFormItem" @copyItem="drawingItemCopy" @deleteItem="drawingItemDelete"/> 87 + <draggable-item
  88 + v-for="(item, index) in drawingList"
  89 + :key="item.renderKey"
  90 + :drawing-list="drawingList"
  91 + :current-item="item"
  92 + :index="index"
  93 + :active-id="activeId"
  94 + :form-conf="formConf"
  95 + @activeItem="activeFormItem"
  96 + @copyItem="drawingItemCopy"
  97 + @deleteItem="drawingItemDelete"
  98 + />
81 </draggable> 99 </draggable>
82 <div v-show="!drawingList.length" class="empty-info"> 100 <div v-show="!drawingList.length" class="empty-info">
83 从左侧拖入或点选组件进行表单设计 101 从左侧拖入或点选组件进行表单设计
@@ -88,52 +106,128 @@ @@ -88,52 +106,128 @@
88 </div> 106 </div>
89 107
90 <!-- 右边:组件属性/表单属性 --> 108 <!-- 右边:组件属性/表单属性 -->
91 - <right-panel :active-data="activeData" :form-conf="formConf" :show-field="!!drawingList.length" @tag-change="tagChange"/> 109 + <right-panel
  110 + :active-data="activeData"
  111 + :form-conf="formConf"
  112 + :show-field="!!drawingList.length"
  113 + @tag-change="tagChange"
  114 + @fetch-data="fetchData"
  115 + />
  116 +
  117 +<!-- <form-drawer-->
  118 +<!-- :visible.sync="drawerVisible"-->
  119 +<!-- :form-data="formData"-->
  120 +<!-- size="100%"-->
  121 +<!-- :generate-conf="generateConf"-->
  122 +<!-- />-->
  123 +
  124 + <json-drawer
  125 + size="60%"
  126 + :visible.sync="jsonDrawerVisible"
  127 + :json-str="JSON.stringify(formData)"
  128 + @refresh="refreshJson"
  129 + />
92 130
  131 +<!-- <code-type-dialog-->
  132 +<!-- :visible.sync="dialogVisible"-->
  133 +<!-- title="选择生成类型"-->
  134 +<!-- :show-file-name="showFileName"-->
  135 +<!-- @confirm="generate"-->
  136 +<!-- />-->
  137 +
  138 +<!-- <input id="copyNode" type="hidden">-->
93 </div> 139 </div>
94 </template> 140 </template>
95 141
96 <script> 142 <script>
97 import draggable from 'vuedraggable' 143 import draggable from 'vuedraggable'
98 -import render from '@/utils/generator/render'  
99 -import { inputComponents, selectComponents, layoutComponents, formConf} from '@/utils/generator/config'  
100 -import drawingDefalut from '@/utils/generator/drawingDefalut'  
101 -// import logo from '@/assets/logo/logo.png'  
102 -import DraggableItem from './../../tool/build/DraggableItem'  
103 -import RightPanel from './../../tool/build/RightPanel'  
104 -import {createForm, getForm, updateForm} from "@/api/bpm/form"; 144 +import { debounce } from 'throttle-debounce'
  145 +import { saveAs } from 'file-saver'
  146 +import ClipboardJS from 'clipboard'
  147 +import render from '@/components/render/render'
  148 +import FormDrawer from '@/views/tool/build/FormDrawer'
  149 +import JsonDrawer from '@/views/tool/build/JsonDrawer'
  150 +import RightPanel from '@/views/tool/build/RightPanel'
  151 +import {
  152 + inputComponents, selectComponents, layoutComponents, formConf
  153 +} from '@/utils/generator/config'
  154 +import {
  155 + exportDefault, beautifierConf, isNumberStr, titleCase, deepClone, isObjectObject
  156 +} from '@/utils/index'
  157 +import {
  158 + makeUpHtml, vueTemplate, vueScript, cssStyle
  159 +} from '@/components/generator/html'
  160 +import { makeUpJs } from '@/components/generator/js'
  161 +import { makeUpCss } from '@/components/generator/css'
  162 +import drawingDefalut from '@/components/generator/drawingDefalut'
  163 +import logo from '@/assets/logo/logo.png'
  164 +import CodeTypeDialog from '@/views/tool/build/CodeTypeDialog'
  165 +import DraggableItem from '@/views/tool/build/DraggableItem'
  166 +import {
  167 + getDrawingList, saveDrawingList, getIdGlobal, saveIdGlobal, getFormConf
  168 +} from '@/utils/db'
  169 +import loadBeautifier from '@/utils/loadBeautifier'
105 import {SysCommonStatusEnum} from "@/utils/constants"; 170 import {SysCommonStatusEnum} from "@/utils/constants";
  171 +import {createForm, getForm, updateForm} from "@/api/bpm/form";
106 172
107 -// const emptyActiveData = { style: {}, autosize: {} } 173 +let beautifier
  174 +const emptyActiveData = { style: {}, autosize: {} }
108 let oldActiveId 175 let oldActiveId
109 let tempActiveData 176 let tempActiveData
  177 +const drawingListInDB = getDrawingList()
  178 +const formConfInDB = getFormConf()
  179 +const idGlobal = getIdGlobal()
110 180
111 export default { 181 export default {
112 components: { 182 components: {
113 draggable, 183 draggable,
114 render, 184 render,
  185 + FormDrawer,
  186 + JsonDrawer,
115 RightPanel, 187 RightPanel,
  188 + CodeTypeDialog,
116 DraggableItem 189 DraggableItem
117 }, 190 },
118 data() { 191 data() {
119 return { 192 return {
120 - // logo,  
121 - idGlobal: 100, // 自动 ID 生成时,全局递增。例如说 field100  
122 - formConf, // 表单格式 193 + logo,
  194 + idGlobal,
  195 + formConf,
123 inputComponents, 196 inputComponents,
124 selectComponents, 197 selectComponents,
125 layoutComponents, 198 layoutComponents,
126 labelWidth: 100, 199 labelWidth: 100,
127 - 200 + // drawingList: drawingDefalut,
128 drawingData: {}, // 生成后的表单数据 201 drawingData: {}, // 生成后的表单数据
  202 + activeId: drawingDefalut[0].__config__.formId,
129 203
130 drawingList: [], // 表单项的数组 204 drawingList: [], // 表单项的数组
131 - activeId: undefined,  
132 - activeData: {},  
133 - // drawerVisible: false,  
134 - // formData: {},  
135 - // dialogVisible: false,  
136 - // showFileName: false, 205 + // activeId: undefined,
  206 + // activeData: {},
  207 +
  208 + drawerVisible: false,
  209 + formData: {},
  210 + dialogVisible: false,
  211 + jsonDrawerVisible: false,
  212 + generateConf: null,
  213 + showFileName: false,
  214 + activeData: drawingDefalut[0], // 右边编辑器激活的表单项
  215 + saveDrawingListDebounce: debounce(340, saveDrawingList),
  216 + saveIdGlobalDebounce: debounce(340, saveIdGlobal),
  217 + leftComponents: [
  218 + {
  219 + title: '输入型组件',
  220 + list: inputComponents
  221 + },
  222 + {
  223 + title: '选择型组件',
  224 + list: selectComponents
  225 + },
  226 + {
  227 + title: '布局型组件',
  228 + list: layoutComponents
  229 + }
  230 + ],
137 231
138 // 表单参数 232 // 表单参数
139 form: { 233 form: {
@@ -146,12 +240,14 @@ export default { @@ -146,12 +240,14 @@ export default {
146 } 240 }
147 } 241 }
148 }, 242 },
  243 + computed: {
  244 + },
149 watch: { 245 watch: {
150 // eslint-disable-next-line func-names 246 // eslint-disable-next-line func-names
151 - 'activeData.label': function (val, oldVal) { 247 + 'activeData.__config__.label': function (val, oldVal) {
152 if ( 248 if (
153 this.activeData.placeholder === undefined 249 this.activeData.placeholder === undefined
154 - || !this.activeData.tag 250 + || !this.activeData.__config__.tag
155 || oldActiveId !== this.activeId 251 || oldActiveId !== this.activeId
156 ) { 252 ) {
157 return 253 return
@@ -163,8 +259,50 @@ export default { @@ -163,8 +259,50 @@ export default {
163 oldActiveId = val 259 oldActiveId = val
164 }, 260 },
165 immediate: true 261 immediate: true
  262 + },
  263 + drawingList: {
  264 + handler(val) {
  265 + this.saveDrawingListDebounce(val)
  266 + if (val.length === 0) this.idGlobal = 100
  267 + },
  268 + deep: true
  269 + },
  270 + idGlobal: {
  271 + handler(val) {
  272 + this.saveIdGlobalDebounce(val)
  273 + },
  274 + immediate: true
166 } 275 }
167 }, 276 },
  277 + mounted() {
  278 + // 【add by 芋道源码】不读缓存
  279 + // if (Array.isArray(drawingListInDB) && drawingListInDB.length > 0) {
  280 + // this.drawingList = drawingListInDB
  281 + // } else {
  282 + // this.drawingList = drawingDefalut
  283 + // }
  284 + // this.activeFormItem(this.drawingList[0])
  285 + // if (formConfInDB) {
  286 + // this.formConf = formConfInDB
  287 + // }
  288 + loadBeautifier(btf => {
  289 + beautifier = btf
  290 + })
  291 + const clipboard = new ClipboardJS('#copyNode', {
  292 + text: trigger => {
  293 + const codeStr = this.generateCode()
  294 + this.$notify({
  295 + title: '成功',
  296 + message: '代码已复制到剪切板,可粘贴。',
  297 + type: 'success'
  298 + })
  299 + return codeStr
  300 + }
  301 + })
  302 + clipboard.on('error', e => {
  303 + this.$message.error('代码复制失败')
  304 + })
  305 + },
168 created() { 306 created() {
169 // 读取表单配置 307 // 读取表单配置
170 const formId = this.$route.query && this.$route.query.formId 308 const formId = this.$route.query && this.$route.query.formId
@@ -179,49 +317,105 @@ export default { @@ -179,49 +317,105 @@ export default {
179 } 317 }
180 this.formConf = JSON.parse(data.conf) 318 this.formConf = JSON.parse(data.conf)
181 this.drawingList = this.decodeFields(data.fields) 319 this.drawingList = this.decodeFields(data.fields)
  320 + // 设置激活的表单项
  321 + this.activeData = this.drawingList[0]
  322 + this.activeId = this.activeData.__config__.formId
182 // 设置 idGlobal,避免重复 323 // 设置 idGlobal,避免重复
183 this.idGlobal += this.drawingList.length 324 this.idGlobal += this.drawingList.length
184 }); 325 });
185 } 326 }
186 }, 327 },
187 methods: { 328 methods: {
188 - activeFormItem(element) {  
189 - this.activeData = element  
190 - this.activeId = element.formId 329 + setObjectValueReduce(obj, strKeys, data) {
  330 + const arr = strKeys.split('.')
  331 + arr.reduce((pre, item, i) => {
  332 + if (arr.length === i + 1) {
  333 + pre[item] = data
  334 + } else if (!isObjectObject(pre[item])) {
  335 + pre[item] = {}
  336 + }
  337 + return pre[item]
  338 + }, obj)
191 }, 339 },
192 - onEnd(obj, a) { 340 + setRespData(component, resp) {
  341 + const { dataPath, renderKey, dataConsumer } = component.__config__
  342 + if (!dataPath || !dataConsumer) return
  343 + const respData = dataPath.split('.').reduce((pre, item) => pre[item], resp)
  344 +
  345 + // 将请求回来的数据,赋值到指定属性。
  346 + // 以el-tabel为例,根据Element文档,应该将数据赋值给el-tabel的data属性,所以dataConsumer的值应为'data';
  347 + // 此时赋值代码可写成 component[dataConsumer] = respData;
  348 + // 但为支持更深层级的赋值(如:dataConsumer的值为'options.data'),使用setObjectValueReduce
  349 + this.setObjectValueReduce(component, dataConsumer, respData)
  350 + const i = this.drawingList.findIndex(item => item.__config__.renderKey === renderKey)
  351 + if (i > -1) this.$set(this.drawingList, i, component)
  352 + },
  353 + fetchData(component) {
  354 + const { dataType, method, url } = component.__config__
  355 + if (dataType === 'dynamic' && method && url) {
  356 + this.setLoading(component, true)
  357 + this.$axios({
  358 + method,
  359 + url
  360 + }).then(resp => {
  361 + this.setLoading(component, false)
  362 + this.setRespData(component, resp.data)
  363 + })
  364 + }
  365 + },
  366 + setLoading(component, val) {
  367 + const { directives } = component
  368 + if (Array.isArray(directives)) {
  369 + const t = directives.find(d => d.name === 'loading')
  370 + if (t) t.value = val
  371 + }
  372 + },
  373 + activeFormItem(currentItem) {
  374 + this.activeData = currentItem
  375 + this.activeId = currentItem.__config__.formId
  376 + },
  377 + onEnd(obj) {
193 if (obj.from !== obj.to) { 378 if (obj.from !== obj.to) {
  379 + this.fetchData(tempActiveData)
194 this.activeData = tempActiveData 380 this.activeData = tempActiveData
195 this.activeId = this.idGlobal 381 this.activeId = this.idGlobal
196 } 382 }
197 }, 383 },
198 addComponent(item) { 384 addComponent(item) {
199 const clone = this.cloneComponent(item) 385 const clone = this.cloneComponent(item)
  386 + this.fetchData(clone)
200 this.drawingList.push(clone) 387 this.drawingList.push(clone)
201 this.activeFormItem(clone) 388 this.activeFormItem(clone)
202 }, 389 },
203 cloneComponent(origin) { 390 cloneComponent(origin) {
204 - const clone = JSON.parse(JSON.stringify(origin))  
205 - clone.formId = ++this.idGlobal  
206 - clone.span = formConf.span  
207 - clone.renderKey = +new Date() // 改变renderKey后可以实现强制更新组件  
208 - if (!clone.layout) clone.layout = 'colFormItem'  
209 - if (clone.layout === 'colFormItem') {  
210 - clone.vModel = `field${this.idGlobal}`  
211 - clone.placeholder !== undefined && (clone.placeholder += clone.label)  
212 - tempActiveData = clone  
213 - } else if (clone.layout === 'rowFormItem') {  
214 - delete clone.label  
215 - clone.componentName = `row${this.idGlobal}`  
216 - clone.gutter = this.formConf.gutter  
217 - tempActiveData = clone  
218 - } 391 + const clone = deepClone(origin)
  392 + const config = clone.__config__
  393 + config.span = this.formConf.span // 生成代码时,会根据span做精简判断
  394 + this.createIdAndKey(clone)
  395 + clone.placeholder !== undefined && (clone.placeholder += config.label)
  396 + tempActiveData = clone
219 return tempActiveData 397 return tempActiveData
220 }, 398 },
  399 + createIdAndKey(item) {
  400 + const config = item.__config__
  401 + config.formId = ++this.idGlobal
  402 + config.renderKey = `${config.formId}${+new Date()}` // 改变renderKey后可以实现强制更新组件
  403 + if (config.layout === 'colFormItem') {
  404 + item.__vModel__ = `field${this.idGlobal}`
  405 + } else if (config.layout === 'rowFormItem') {
  406 + config.componentName = `row${this.idGlobal}`
  407 + !Array.isArray(config.children) && (config.children = [])
  408 + delete config.label // rowFormItem无需配置label属性
  409 + }
  410 + if (Array.isArray(config.children)) {
  411 + config.children = config.children.map(childItem => this.createIdAndKey(childItem))
  412 + }
  413 + return item
  414 + },
221 // 获得表单数据 415 // 获得表单数据
222 AssembleFormData() { 416 AssembleFormData() {
223 this.formData = { 417 this.formData = {
224 - fields: JSON.parse(JSON.stringify(this.drawingList)), 418 + fields: deepClone(this.drawingList),
225 ...this.formConf 419 ...this.formConf
226 } 420 }
227 }, 421 },
@@ -272,34 +466,39 @@ export default { @@ -272,34 +466,39 @@ export default {
272 }) 466 })
273 return drawingList 467 return drawingList
274 }, 468 },
  469 + generate(data) {
  470 + const func = this[`exec${titleCase(this.operationType)}`]
  471 + this.generateConf = data
  472 + func && func(data)
  473 + },
  474 + execRun(data) {
  475 + this.AssembleFormData()
  476 + this.drawerVisible = true
  477 + },
  478 + execDownload(data) {
  479 + const codeStr = this.generateCode()
  480 + const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
  481 + saveAs(blob, data.fileName)
  482 + },
  483 + execCopy(data) {
  484 + document.getElementById('copyNode').click()
  485 + },
275 empty() { 486 empty() {
276 this.$confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then( 487 this.$confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then(
277 () => { 488 () => {
278 this.drawingList = [] 489 this.drawingList = []
  490 + this.idGlobal = 100
279 } 491 }
280 ) 492 )
281 }, 493 },
282 - drawingItemCopy(item, parent) {  
283 - let clone = JSON.parse(JSON.stringify(item)) 494 + drawingItemCopy(item, list) {
  495 + let clone = deepClone(item)
284 clone = this.createIdAndKey(clone) 496 clone = this.createIdAndKey(clone)
285 - parent.push(clone) 497 + list.push(clone)
286 this.activeFormItem(clone) 498 this.activeFormItem(clone)
287 }, 499 },
288 - createIdAndKey(item) {  
289 - item.formId = ++this.idGlobal  
290 - item.renderKey = +new Date()  
291 - if (item.layout === 'colFormItem') {  
292 - item.vModel = `field${this.idGlobal}`  
293 - } else if (item.layout === 'rowFormItem') {  
294 - item.componentName = `row${this.idGlobal}`  
295 - }  
296 - if (Array.isArray(item.children)) {  
297 - item.children = item.children.map(childItem => this.createIdAndKey(childItem))  
298 - }  
299 - return item  
300 - },  
301 - drawingItemDelete(index, parent) {  
302 - parent.splice(index, 1) 500 + drawingItemDelete(index, list) {
  501 + list.splice(index, 1)
303 this.$nextTick(() => { 502 this.$nextTick(() => {
304 const len = this.drawingList.length 503 const len = this.drawingList.length
305 if (len) { 504 if (len) {
@@ -307,17 +506,47 @@ export default { @@ -307,17 +506,47 @@ export default {
307 } 506 }
308 }) 507 })
309 }, 508 },
  509 + generateCode() {
  510 + const { type } = this.generateConf
  511 + this.AssembleFormData()
  512 + const script = vueScript(makeUpJs(this.formData, type))
  513 + const html = vueTemplate(makeUpHtml(this.formData, type))
  514 + const css = cssStyle(makeUpCss(this.formData))
  515 + return beautifier.html(html + script + css, beautifierConf.html)
  516 + },
  517 + showJson() {
  518 + this.AssembleFormData()
  519 + this.jsonDrawerVisible = true
  520 + },
  521 + download() {
  522 + this.dialogVisible = true
  523 + this.showFileName = true
  524 + this.operationType = 'download'
  525 + },
  526 + run() {
  527 + this.dialogVisible = true
  528 + this.showFileName = false
  529 + this.operationType = 'run'
  530 + },
  531 + copy() {
  532 + this.dialogVisible = true
  533 + this.showFileName = false
  534 + this.operationType = 'copy'
  535 + },
310 tagChange(newTag) { 536 tagChange(newTag) {
311 newTag = this.cloneComponent(newTag) 537 newTag = this.cloneComponent(newTag)
312 - newTag.vModel = this.activeData.vModel  
313 - newTag.formId = this.activeId  
314 - newTag.span = this.activeData.span  
315 - delete this.activeData.tag  
316 - delete this.activeData.tagIcon  
317 - delete this.activeData.document 538 + const config = newTag.__config__
  539 + newTag.__vModel__ = this.activeData.__vModel__
  540 + config.formId = this.activeId
  541 + config.span = this.activeData.__config__.span
  542 + this.activeData.__config__.tag = config.tag
  543 + this.activeData.__config__.tagIcon = config.tagIcon
  544 + this.activeData.__config__.document = config.document
  545 + if (typeof this.activeData.__config__.defaultValue === typeof config.defaultValue) {
  546 + config.defaultValue = this.activeData.__config__.defaultValue
  547 + }
318 Object.keys(newTag).forEach(key => { 548 Object.keys(newTag).forEach(key => {
319 - if (this.activeData[key] !== undefined  
320 - && typeof this.activeData[key] === typeof newTag[key]) { 549 + if (this.activeData[key] !== undefined) {
321 newTag[key] = this.activeData[key] 550 newTag[key] = this.activeData[key]
322 } 551 }
323 }) 552 })
@@ -325,414 +554,24 @@ export default { @@ -325,414 +554,24 @@ export default {
325 this.updateDrawingList(newTag, this.drawingList) 554 this.updateDrawingList(newTag, this.drawingList)
326 }, 555 },
327 updateDrawingList(newTag, list) { 556 updateDrawingList(newTag, list) {
328 - const index = list.findIndex(item => item.formId === this.activeId) 557 + const index = list.findIndex(item => item.__config__.formId === this.activeId)
329 if (index > -1) { 558 if (index > -1) {
330 list.splice(index, 1, newTag) 559 list.splice(index, 1, newTag)
331 } else { 560 } else {
332 list.forEach(item => { 561 list.forEach(item => {
333 - if (Array.isArray(item.children)) this.updateDrawingList(newTag, item.children) 562 + if (Array.isArray(item.__config__.children)) this.updateDrawingList(newTag, item.__config__.children)
334 }) 563 })
335 } 564 }
  565 + },
  566 + refreshJson(data) {
  567 + this.drawingList = deepClone(data.fields)
  568 + delete data.fields
  569 + this.formConf = data
336 } 570 }
337 } 571 }
338 } 572 }
339 </script> 573 </script>
340 574
341 <style lang='scss'> 575 <style lang='scss'>
342 -body, html{  
343 - margin: 0;  
344 - padding: 0;  
345 - background: #fff;  
346 - -moz-osx-font-smoothing: grayscale;  
347 - -webkit-font-smoothing: antialiased;  
348 - text-rendering: optimizeLegibility;  
349 - font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;  
350 -}  
351 -  
352 -input, textarea{  
353 - font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;  
354 -}  
355 -  
356 -.editor-tabs{  
357 - background: #121315;  
358 - .el-tabs__header{  
359 - margin: 0;  
360 - border-bottom-color: #121315;  
361 - .el-tabs__nav{  
362 - border-color: #121315;  
363 - }  
364 - }  
365 - .el-tabs__item{  
366 - height: 32px;  
367 - line-height: 32px;  
368 - color: #888a8e;  
369 - border-left: 1px solid #121315 !important;  
370 - background: #363636;  
371 - margin-right: 5px;  
372 - user-select: none;  
373 - }  
374 - .el-tabs__item.is-active{  
375 - background: #1e1e1e;  
376 - border-bottom-color: #1e1e1e!important;  
377 - color: #fff;  
378 - }  
379 - .el-icon-edit{  
380 - color: #f1fa8c;  
381 - }  
382 - .el-icon-document{  
383 - color: #a95812;  
384 - }  
385 -}  
386 -  
387 -// home  
388 -.right-scrollbar {  
389 - .el-scrollbar__view {  
390 - padding: 12px 18px 15px 15px;  
391 - }  
392 -}  
393 -.left-scrollbar .el-scrollbar__wrap {  
394 - box-sizing: border-box;  
395 - overflow-x: hidden !important;  
396 - margin-bottom: 0 !important;  
397 -}  
398 -.center-tabs{  
399 - .el-tabs__header{  
400 - margin-bottom: 0!important;  
401 - }  
402 - .el-tabs__item{  
403 - width: 50%;  
404 - text-align: center;  
405 - }  
406 - .el-tabs__nav{  
407 - width: 100%;  
408 - }  
409 -}  
410 -.reg-item{  
411 - padding: 12px 6px;  
412 - background: #f8f8f8;  
413 - position: relative;  
414 - border-radius: 4px;  
415 - .close-btn{  
416 - position: absolute;  
417 - right: -6px;  
418 - top: -6px;  
419 - display: block;  
420 - width: 16px;  
421 - height: 16px;  
422 - line-height: 16px;  
423 - background: rgba(0, 0, 0, 0.2);  
424 - border-radius: 50%;  
425 - color: #fff;  
426 - text-align: center;  
427 - z-index: 1;  
428 - cursor: pointer;  
429 - font-size: 12px;  
430 - &:hover{  
431 - background: rgba(210, 23, 23, 0.5)  
432 - }  
433 - }  
434 - & + .reg-item{  
435 - margin-top: 18px;  
436 - }  
437 -}  
438 -.action-bar{  
439 - & .el-button+.el-button {  
440 - margin-left: 15px;  
441 - }  
442 - & i {  
443 - font-size: 20px;  
444 - vertical-align: middle;  
445 - position: relative;  
446 - top: -1px;  
447 - }  
448 -}  
449 -  
450 -.custom-tree-node{  
451 - width: 100%;  
452 - font-size: 14px;  
453 - .node-operation{  
454 - float: right;  
455 - }  
456 - i[class*="el-icon"] + i[class*="el-icon"]{  
457 - margin-left: 6px;  
458 - }  
459 - .el-icon-plus{  
460 - color: #409EFF;  
461 - }  
462 - .el-icon-delete{  
463 - color: #157a0c;  
464 - }  
465 -}  
466 -  
467 -.left-scrollbar .el-scrollbar__view{  
468 - overflow-x: hidden;  
469 -}  
470 -  
471 -.el-rate{  
472 - display: inline-block;  
473 - vertical-align: text-top;  
474 -}  
475 -.el-upload__tip{  
476 - line-height: 1.2;  
477 -}  
478 -  
479 -$selectedColor: #f6f7ff;  
480 -$lighterBlue: #409EFF;  
481 -  
482 -.container {  
483 - position: relative;  
484 - width: 100%;  
485 - height: 100%;  
486 -}  
487 -  
488 -.components-list {  
489 - padding: 8px;  
490 - box-sizing: border-box;  
491 - height: 100%;  
492 - .components-item {  
493 - display: inline-block;  
494 - width: 48%;  
495 - margin: 1%;  
496 - transition: transform 0ms !important;  
497 - }  
498 -}  
499 -.components-draggable{  
500 - padding-bottom: 20px;  
501 -}  
502 -.components-title{  
503 - font-size: 14px;  
504 - color: #222;  
505 - margin: 6px 2px;  
506 - .svg-icon{  
507 - color: #666;  
508 - font-size: 18px;  
509 - }  
510 -}  
511 -  
512 -.components-body {  
513 - padding: 8px 10px;  
514 - background: $selectedColor;  
515 - font-size: 12px;  
516 - cursor: move;  
517 - border: 1px dashed $selectedColor;  
518 - border-radius: 3px;  
519 - .svg-icon{  
520 - color: #777;  
521 - font-size: 15px;  
522 - }  
523 - &:hover {  
524 - border: 1px dashed #787be8;  
525 - color: #787be8;  
526 - .svg-icon {  
527 - color: #787be8;  
528 - }  
529 - }  
530 -}  
531 -  
532 -.left-board {  
533 - width: 260px;  
534 - position: absolute;  
535 - left: 0;  
536 - top: 0;  
537 - height: 100vh;  
538 -}  
539 -.left-scrollbar{  
540 - height: calc(100vh - 42px);  
541 - overflow: hidden;  
542 -}  
543 -.center-scrollbar {  
544 - height: calc(100vh - 42px);  
545 - overflow: hidden;  
546 - border-left: 1px solid #f1e8e8;  
547 - border-right: 1px solid #f1e8e8;  
548 - box-sizing: border-box;  
549 -}  
550 -.center-board {  
551 - height: 100vh;  
552 - width: auto;  
553 - margin: 0 350px 0 260px;  
554 - box-sizing: border-box;  
555 -}  
556 -.empty-info{  
557 - position: absolute;  
558 - top: 46%;  
559 - left: 0;  
560 - right: 0;  
561 - text-align: center;  
562 - font-size: 18px;  
563 - color: #ccb1ea;  
564 - letter-spacing: 4px;  
565 -}  
566 -.action-bar{  
567 - position: relative;  
568 - height: 42px;  
569 - text-align: right;  
570 - padding: 0 15px;  
571 - box-sizing: border-box;;  
572 - border: 1px solid #f1e8e8;  
573 - border-top: none;  
574 - border-left: none;  
575 - .delete-btn{  
576 - color: #F56C6C;  
577 - }  
578 -}  
579 -.logo-wrapper{  
580 - position: relative;  
581 - height: 42px;  
582 - background: #fff;  
583 - border-bottom: 1px solid #f1e8e8;  
584 - box-sizing: border-box;  
585 -}  
586 -.logo{  
587 - position: absolute;  
588 - left: 12px;  
589 - top: 6px;  
590 - line-height: 30px;  
591 - color: #00afff;  
592 - font-weight: 600;  
593 - font-size: 17px;  
594 - white-space: nowrap;  
595 -}  
596 -  
597 -.center-board-row {  
598 - padding: 12px 12px 15px 12px;  
599 - box-sizing: border-box;  
600 - & > .el-form {  
601 - // 69 = 12+15+42  
602 - height: calc(100vh - 69px);  
603 - }  
604 -}  
605 -.drawing-board {  
606 - height: 100%;  
607 - position: relative;  
608 - .components-body {  
609 - padding: 0;  
610 - margin: 0;  
611 - font-size: 0;  
612 - }  
613 - .sortable-ghost {  
614 - position: relative;  
615 - display: block;  
616 - overflow: hidden;  
617 - &::before {  
618 - content: " ";  
619 - position: absolute;  
620 - left: 0;  
621 - right: 0;  
622 - top: 0;  
623 - height: 3px;  
624 - background: rgb(89, 89, 223);  
625 - z-index: 2;  
626 - }  
627 - }  
628 - .components-item.sortable-ghost {  
629 - width: 100%;  
630 - height: 60px;  
631 - background-color: $selectedColor;  
632 - }  
633 - .active-from-item {  
634 - & > .el-form-item{  
635 - background: $selectedColor;  
636 - border-radius: 6px;  
637 - }  
638 - & > .drawing-item-copy, & > .drawing-item-delete{  
639 - display: initial;  
640 - }  
641 - & > .component-name{  
642 - color: $lighterBlue;  
643 - }  
644 - }  
645 - .el-form-item{  
646 - margin-bottom: 15px;  
647 - }  
648 -}  
649 -.drawing-item{  
650 - position: relative;  
651 - cursor: move;  
652 - &.unfocus-bordered:not(.activeFromItem) > div:first-child {  
653 - border: 1px dashed #ccc;  
654 - }  
655 - .el-form-item{  
656 - padding: 12px 10px;  
657 - }  
658 -}  
659 -.drawing-row-item{  
660 - position: relative;  
661 - cursor: move;  
662 - box-sizing: border-box;  
663 - border: 1px dashed #ccc;  
664 - border-radius: 3px;  
665 - padding: 0 2px;  
666 - margin-bottom: 15px;  
667 - .drawing-row-item {  
668 - margin-bottom: 2px;  
669 - }  
670 - .el-col{  
671 - margin-top: 22px;  
672 - }  
673 - .el-form-item{  
674 - margin-bottom: 0;  
675 - }  
676 - .drag-wrapper{  
677 - min-height: 80px;  
678 - }  
679 - &.active-from-item{  
680 - border: 1px dashed $lighterBlue;  
681 - }  
682 - .component-name{  
683 - position: absolute;  
684 - top: 0;  
685 - left: 0;  
686 - font-size: 12px;  
687 - color: #bbb;  
688 - display: inline-block;  
689 - padding: 0 6px;  
690 - }  
691 -}  
692 -.drawing-item, .drawing-row-item{  
693 - &:hover {  
694 - & > .el-form-item{  
695 - background: $selectedColor;  
696 - border-radius: 6px;  
697 - }  
698 - & > .drawing-item-copy, & > .drawing-item-delete{  
699 - display: initial;  
700 - }  
701 - }  
702 - & > .drawing-item-copy, & > .drawing-item-delete{  
703 - display: none;  
704 - position: absolute;  
705 - top: -10px;  
706 - width: 22px;  
707 - height: 22px;  
708 - line-height: 22px;  
709 - text-align: center;  
710 - border-radius: 50%;  
711 - font-size: 12px;  
712 - border: 1px solid;  
713 - cursor: pointer;  
714 - z-index: 1;  
715 - }  
716 - & > .drawing-item-copy{  
717 - right: 56px;  
718 - border-color: $lighterBlue;  
719 - color: $lighterBlue;  
720 - background: #fff;  
721 - &:hover{  
722 - background: $lighterBlue;  
723 - color: #fff;  
724 - }  
725 - }  
726 - & > .drawing-item-delete{  
727 - right: 24px;  
728 - border-color: #F56C6C;  
729 - color: #F56C6C;  
730 - background: #fff;  
731 - &:hover{  
732 - background: #F56C6C;  
733 - color: #fff;  
734 - }  
735 - }  
736 -}  
737 - 576 +@import '@/styles/home';
738 </style> 577 </style>
yudao-admin-ui/src/views/tool/build/README.md 0 → 100644
  1 +【add by 芋道源码】引自 https://github.com/JakHuang/form-generator/tree/dev/src/views/index 目录
0 \ No newline at end of file 2 \ No newline at end of file