1.表单设计器增加初始化属性;2.增加组件层次结构树视图;3.修复少量bug。
|
@ -9,7 +9,7 @@
|
|||
[在线Demo](http://demo.vform666.com)
|
||||
|
||||
### 友情链接
|
||||
[fantastic-admin](https://hooray.gitee.io/fantastic-admin/) —— 一款开箱即用的 Vue 中后台管理系统框架(支持Vue2/Vue3)
|
||||
[Fantastic-admin](https://hooray.gitee.io/fantastic-admin/) —— 一款开箱即用的 Vue 中后台管理系统框架(支持Vue2/Vue3)
|
||||
|
||||
<br/>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "variant-form",
|
||||
"version": "2.1.7",
|
||||
"version": "2.1.8",
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve --open src/main.js",
|
||||
|
|
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 50 KiB |
|
@ -62,7 +62,7 @@ export function createDesigner(vueInstance) {
|
|||
this.initHistoryData()
|
||||
},
|
||||
|
||||
clearDesigner() {
|
||||
clearDesigner(skipHistoryChange) {
|
||||
let emptyWidgetListFlag = (this.widgetList.length === 0)
|
||||
this.widgetList = []
|
||||
this.selectedId = null
|
||||
|
@ -70,7 +70,9 @@ export function createDesigner(vueInstance) {
|
|||
this.selectedWidget = {} //this.selectedWidget = null
|
||||
overwriteObj(this.formConfig, defaultFormConfig) //
|
||||
|
||||
if (!emptyWidgetListFlag) {
|
||||
if (!!skipHistoryChange) {
|
||||
//什么也不做!!
|
||||
} else if (!emptyWidgetListFlag) {
|
||||
this.emitHistoryChange()
|
||||
} else {
|
||||
this.saveCurrentHistoryStep()
|
||||
|
@ -618,7 +620,14 @@ export function createDesigner(vueInstance) {
|
|||
let newWidget = this.copyNewFieldWidget(widget)
|
||||
if (!!this.selectedWidget && this.selectedWidget.type === 'tab') {
|
||||
//获取当前激活的tabPane
|
||||
//TODO:
|
||||
let activeTab = this.selectedWidget.tabs[0]
|
||||
this.selectedWidget.tabs.forEach(tabPane => {
|
||||
if (!!tabPane.options.active) {
|
||||
activeTab = tabPane
|
||||
}
|
||||
})
|
||||
|
||||
!!activeTab && activeTab.widgetList.push(newWidget)
|
||||
} else if (!!this.selectedWidget && !!this.selectedWidget.widgetList) {
|
||||
this.selectedWidget.widgetList.push(newWidget)
|
||||
} else {
|
||||
|
@ -626,6 +635,7 @@ export function createDesigner(vueInstance) {
|
|||
}
|
||||
|
||||
this.setSelected(newWidget)
|
||||
this.designer.emitHistoryChange()
|
||||
},
|
||||
|
||||
deleteColOfGrid(gridWidget, colIdx) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<el-col v-else-if="widget.type === 'grid-col'" class="grid-cell" v-bind="layoutProps"
|
||||
:class="[selected ? 'selected' : '', customClass]"
|
||||
:class="[selected ? 'selected' : '', customClass]" :style="colHeightStyle"
|
||||
:key="widget.id" @click.native.stop="selectWidget(widget)">
|
||||
<draggable :list="widget.widgetList" v-bind="{group:'dragGroup', ghostClass: 'ghost',animation: 200}"
|
||||
handle=".drag-handler" @end="(evt) => onGridDragEnd(evt, widget.widgetList)"
|
||||
|
@ -56,6 +56,12 @@
|
|||
parentList: Array,
|
||||
indexOfParentList: Number,
|
||||
designer: Object,
|
||||
|
||||
colHeight: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -79,6 +85,10 @@
|
|||
return this.widget.options.customClass || ''
|
||||
},
|
||||
|
||||
colHeightStyle() {
|
||||
return !!this.colHeight ? {height: this.colHeight + 'px'} : {}
|
||||
},
|
||||
|
||||
},
|
||||
watch: {
|
||||
'designer.formConfig.layoutType': {
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
@click.native.stop="selectWidget(widget)">
|
||||
<template v-for="(colWidget, colIdx) in widget.cols">
|
||||
<grid-col-widget :widget="colWidget" :designer="designer" :key="colWidget.id" :parent-list="widget.cols"
|
||||
:index-of-parent-list="colIdx" :parent-widget="widget"></grid-col-widget>
|
||||
:index-of-parent-list="colIdx" :parent-widget="widget"
|
||||
:col-height="widget.options.colHeight"></grid-col-widget>
|
||||
</template>
|
||||
</el-row>
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import {deepClone} from "@/utils/util"
|
|||
import FormValidators from '@/utils/validators'
|
||||
|
||||
export default {
|
||||
inject: ['refList', 'formConfig', 'globalOptionData', 'globalModel'],
|
||||
inject: ['refList', 'formConfig', 'globalOptionData', 'globalModel', 'getOptionData'],
|
||||
|
||||
computed: {
|
||||
subFormName() {
|
||||
|
@ -100,7 +100,7 @@ export default {
|
|||
})
|
||||
|
||||
/* 监听重新加载选项事件 */
|
||||
this.$on('reloadOptions', function (widgetNames) {
|
||||
this.$on('reloadOptionItems', function (widgetNames) {
|
||||
if ((widgetNames.length === 0) || (widgetNames.indexOf(this.field.options.name) > -1)) {
|
||||
this.initOptionItems(true)
|
||||
}
|
||||
|
@ -157,7 +157,10 @@ export default {
|
|||
|| (this.field.type === 'select') || (this.field.type === 'cascader')) {
|
||||
if (!!this.globalOptionData && this.globalOptionData.hasOwnProperty(this.field.options.name)) {
|
||||
if (!!keepSelected) {
|
||||
this.reloadOptions(this.globalOptionData[this.field.options.name])
|
||||
//this.reloadOptions(this.globalOptionData[this.field.options.name]) /* 异步更新option-data之后不能获取到最新值,
|
||||
// 以下改用provide的getOptionData()方法 */
|
||||
const newOptionItems = this.getOptionData()
|
||||
this.reloadOptions(newOptionItems[this.field.options.name])
|
||||
} else {
|
||||
this.loadOptions( this.globalOptionData[this.field.options.name] )
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
refList: this.widgetRefList,
|
||||
formConfig: this.formConfig,
|
||||
globalOptionData: this.optionData,
|
||||
getOptionData: () => this.optionData,
|
||||
globalModel: {
|
||||
formModel: this.formModel,
|
||||
}
|
||||
|
@ -222,7 +223,7 @@
|
|||
|
||||
.el-form.Pad-layout {
|
||||
margin: 0 auto;
|
||||
width: 960px;
|
||||
max-width: 960px;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 0 1px 10px #495060;
|
||||
}
|
||||
|
|
|
@ -15,17 +15,17 @@
|
|||
<img src="../../assets/vform-logo.png" @click="openHome">
|
||||
<span class="bold">VForm</span> {{i18nt('application.productTitle')}} <span class="version-span">Ver {{vFormVersion}}</span></div>
|
||||
<div class="float-right external-link">
|
||||
<el-dropdown @command="handleLanguageChanged">
|
||||
<el-dropdown v-if="showLink('languageMenu')" @command="handleLanguageChanged">
|
||||
<span class="el-dropdown-link">{{curLangName}}<i class="el-icon-arrow-down el-icon--right"></i></span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="zh-CN">{{i18nt('application.zh-CN')}}</el-dropdown-item>
|
||||
<el-dropdown-item command="en-US">{{i18nt('application.en-US')}}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
<a href="javascript:void(0)" @click="(ev) => openUrl(ev, gitUrl)" target="_blank"><svg-icon icon-class="github" />{{i18nt('application.github')}}</a>
|
||||
<a href="javascript:void(0)" @click="(ev) => openUrl(ev, docUrl)" target="_blank"><svg-icon icon-class="document" />{{i18nt('application.document')}}</a>
|
||||
<a href="javascript:void(0)" @click="(ev) => openUrl(ev, chatUrl)" target="_blank">{{i18nt('application.qqGroup')}}</a>
|
||||
<a href="javascript:void(0)" @click="(ev) => openUrl(ev, subScribeUrl)" target="_blank">
|
||||
<a v-if="showLink('externalLink')" href="javascript:void(0)" @click="(ev) => openUrl(ev, gitUrl)" target="_blank"><svg-icon icon-class="github" />{{i18nt('application.github')}}</a>
|
||||
<a v-if="showLink('externalLink')" href="javascript:void(0)" @click="(ev) => openUrl(ev, docUrl)" target="_blank"><svg-icon icon-class="document" />{{i18nt('application.document')}}</a>
|
||||
<a v-if="showLink('externalLink')" href="javascript:void(0)" @click="(ev) => openUrl(ev, chatUrl)" target="_blank">{{i18nt('application.qqGroup')}}</a>
|
||||
<a v-if="showLink('externalLink')" href="javascript:void(0)" @click="(ev) => openUrl(ev, subScribeUrl)" target="_blank">
|
||||
{{i18nt('application.subscription')}}<i class="el-icon-top-right"></i></a>
|
||||
</div>
|
||||
</el-header>
|
||||
|
@ -37,7 +37,9 @@
|
|||
|
||||
<el-container class="center-layout-container">
|
||||
<el-header class="toolbar-header">
|
||||
<toolbar-panel :designer="designer"></toolbar-panel>
|
||||
<toolbar-panel :designer="designer" ref="toolbarRef">
|
||||
<template #toolButton><slot name="customToolButtons"></slot></template>
|
||||
</toolbar-panel>
|
||||
</el-header>
|
||||
<el-main class="form-widget-main">
|
||||
<el-scrollbar class="container-scroll-bar" :style="{height: scrollerHeight}">
|
||||
|
@ -76,10 +78,36 @@
|
|||
VFormWidget,
|
||||
},
|
||||
props: {
|
||||
/* 后端字段列表API */
|
||||
fieldListApi: {
|
||||
type: Object,
|
||||
default: null,
|
||||
}
|
||||
},
|
||||
|
||||
/* 禁止显示的组件名称数组 */
|
||||
bannedWidgets: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
|
||||
designerConfig: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
languageMenu: true, //是否显示语言切换菜单
|
||||
externalLink: true, //是否显示GitHub、文档等外部链接
|
||||
formTemplates: true, //是否显示表单模板
|
||||
eventCollapse: true, //是否显示组件事件属性折叠面板
|
||||
clearDesignerButton: true, //是否显示清空设计器按钮
|
||||
previewFormButton: true, //是否显示预览表单按钮
|
||||
importJsonButton: true, //是否显示导入JSON按钮
|
||||
exportJsonButton: true, //是否显示导出JSON器按钮
|
||||
exportCodeButton: true, //是否显示导出代码按钮
|
||||
generateSFCButton: true, //是否显示生成SFC按钮
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -104,6 +132,8 @@
|
|||
provide() {
|
||||
return {
|
||||
serverFieldList: this.fieldList,
|
||||
getDesignerConfig: () => this.designerConfig,
|
||||
getBannedWidgets: () => this.bannedWidgets,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -125,6 +155,14 @@
|
|||
this.loadFieldListFromServer()
|
||||
},
|
||||
methods: {
|
||||
showLink(configName) {
|
||||
if (this.designerConfig[configName] === undefined) {
|
||||
return true
|
||||
}
|
||||
|
||||
return !!this.designerConfig[configName]
|
||||
},
|
||||
|
||||
openHome() {
|
||||
if (!!this.vsCodeFlag) {
|
||||
const msgObj = {
|
||||
|
@ -233,6 +271,57 @@
|
|||
}
|
||||
},
|
||||
|
||||
clearDesigner() {
|
||||
this.$refs.toolbarRef.clearFormWidget()
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 刷新表单设计器
|
||||
*/
|
||||
refreshDesigner() {
|
||||
//this.designer.loadFormJson( this.getFormJson() ) //只有第一次调用生效??
|
||||
|
||||
let fJson = this.getFormJson()
|
||||
this.designer.clearDesigner(true) //不触发历史记录变更
|
||||
this.designer.loadFormJson(fJson)
|
||||
},
|
||||
|
||||
/**
|
||||
* 预览表单
|
||||
*/
|
||||
previewForm() {
|
||||
this.$refs.toolbarRef.previewForm()
|
||||
},
|
||||
|
||||
/**
|
||||
* 导入表单JSON
|
||||
*/
|
||||
importJson() {
|
||||
this.$refs.toolbarRef.importJson()
|
||||
},
|
||||
|
||||
/**
|
||||
* 导出表单JSON
|
||||
*/
|
||||
exportJson() {
|
||||
this.$refs.toolbarRef.exportJson()
|
||||
},
|
||||
|
||||
/**
|
||||
* 导出Vue/HTML代码
|
||||
*/
|
||||
exportCode() {
|
||||
this.$refs.toolbarRef.exportCode()
|
||||
},
|
||||
|
||||
/**
|
||||
* 生成SFC代码
|
||||
*/
|
||||
generateSFC() {
|
||||
this.$refs.toolbarRef.generateSFC()
|
||||
},
|
||||
|
||||
//TODO: 增加更多方法!!
|
||||
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
</el-form-item>
|
||||
</el-collapse-item>
|
||||
|
||||
<el-collapse-item name="2" :title="i18nt('designer.setting.eventSetting')">
|
||||
<el-collapse-item v-if="showEventCollapse()" name="2" :title="i18nt('designer.setting.eventSetting')">
|
||||
<el-form-item label="onFormCreated" label-width="150px">
|
||||
<el-button type="info" icon="el-icon-edit" plain round @click="editFormEventHandler('onFormCreated')">
|
||||
{{i18nt('designer.setting.addEventHandler')}}</el-button>
|
||||
|
@ -136,8 +136,11 @@
|
|||
designer: Object,
|
||||
formConfig: Object,
|
||||
},
|
||||
inject: ['getDesignerConfig'],
|
||||
data() {
|
||||
return {
|
||||
designerConfig: this.getDesignerConfig(),
|
||||
|
||||
formActiveCollapseNames: ['1', '2'],
|
||||
|
||||
formSizes: [
|
||||
|
@ -188,6 +191,14 @@
|
|||
}, 1200)
|
||||
},
|
||||
methods: {
|
||||
showEventCollapse() {
|
||||
if (this.designerConfig['eventCollapse'] === undefined) {
|
||||
return true
|
||||
}
|
||||
|
||||
return !!this.designerConfig['eventCollapse']
|
||||
},
|
||||
|
||||
editFormCss() {
|
||||
this.formCssCode = this.designer.formConfig.cssCode
|
||||
this.showEditFormCssDialogFlag = true
|
||||
|
|
|
@ -8,21 +8,21 @@
|
|||
<el-form :model="optionModel" size="mini" label-position="left" label-width="120px" class="setting-form"
|
||||
@submit.native.prevent>
|
||||
<el-collapse v-model="widgetActiveCollapseNames" class="setting-collapse">
|
||||
<el-collapse-item name="1" :title="i18nt('designer.setting.commonSetting')">
|
||||
<el-collapse-item name="1" v-if="showCollapse(commonProps)" :title="i18nt('designer.setting.commonSetting')">
|
||||
<template v-for="(editorName, propName) in commonProps">
|
||||
<component v-if="hasPropEditor(propName, editorName)" :is="getPropEditor(propName, editorName)"
|
||||
:designer="designer" :selected-widget="selectedWidget" :option-model="optionModel"></component>
|
||||
</template>
|
||||
</el-collapse-item>
|
||||
|
||||
<el-collapse-item name="2" :title="i18nt('designer.setting.advancedSetting')">
|
||||
<el-collapse-item name="2" v-if="showCollapse(advProps)" :title="i18nt('designer.setting.advancedSetting')">
|
||||
<template v-for="(editorName, propName) in advProps">
|
||||
<component v-if="hasPropEditor(propName, editorName)" :is="getPropEditor(propName, editorName)"
|
||||
:designer="designer" :selected-widget="selectedWidget" :option-model="optionModel"></component>
|
||||
</template>
|
||||
</el-collapse-item>
|
||||
|
||||
<el-collapse-item name="3" :title="i18nt('designer.setting.eventSetting')">
|
||||
<el-collapse-item name="3" v-if="showEventCollapse() && showCollapse(eventProps)" :title="i18nt('designer.setting.eventSetting')">
|
||||
<template v-for="(editorName, propName) in eventProps">
|
||||
<component v-if="hasPropEditor(propName, editorName)" :is="getPropEditor(propName, editorName)"
|
||||
:designer="designer" :selected-widget="selectedWidget" :option-model="optionModel"></component>
|
||||
|
@ -37,21 +37,21 @@
|
|||
<el-form :model="optionModel" size="mini" label-position="left" label-width="120px" class="setting-form"
|
||||
@submit.native.prevent>
|
||||
<el-collapse v-model="widgetActiveCollapseNames" class="setting-collapse">
|
||||
<el-collapse-item name="1" :title="i18nt('designer.setting.commonSetting')">
|
||||
<el-collapse-item name="1" v-if="showCollapse(commonProps)" :title="i18nt('designer.setting.commonSetting')">
|
||||
<template v-for="(editorName, propName) in commonProps">
|
||||
<component v-if="hasPropEditor(propName, editorName)" :is="getPropEditor(propName, editorName)"
|
||||
:designer="designer" :selected-widget="selectedWidget" :option-model="optionModel"></component>
|
||||
</template>
|
||||
</el-collapse-item>
|
||||
|
||||
<el-collapse-item name="2" :title="i18nt('designer.setting.advancedSetting')">
|
||||
<el-collapse-item name="2" v-if="showCollapse(advProps)" :title="i18nt('designer.setting.advancedSetting')">
|
||||
<template v-for="(editorName, propName) in advProps">
|
||||
<component v-if="hasPropEditor(propName, editorName)" :is="getPropEditor(propName, editorName)"
|
||||
:designer="designer" :selected-widget="selectedWidget" :option-model="optionModel"></component>
|
||||
</template>
|
||||
</el-collapse-item>
|
||||
|
||||
<el-collapse-item name="3" :title="i18nt('designer.setting.eventSetting')">
|
||||
<el-collapse-item name="3" v-if="showEventCollapse() && showCollapse(eventProps)" :title="i18nt('designer.setting.eventSetting')">
|
||||
<template v-for="(editorName, propName) in eventProps">
|
||||
<component v-if="hasPropEditor(propName, editorName)" :is="getPropEditor(propName, editorName)"
|
||||
:designer="designer" :selected-widget="selectedWidget" :option-model="optionModel"></component>
|
||||
|
@ -114,8 +114,11 @@
|
|||
selectedWidget: Object,
|
||||
formConfig: Object,
|
||||
},
|
||||
inject: ['getDesignerConfig'],
|
||||
data() {
|
||||
return {
|
||||
designerConfig: this.getDesignerConfig(),
|
||||
|
||||
scrollerHeight: 0,
|
||||
|
||||
activeTab: "2",
|
||||
|
@ -195,6 +198,14 @@
|
|||
})
|
||||
},
|
||||
methods: {
|
||||
showEventCollapse() {
|
||||
if (this.designerConfig['eventCollapse'] === undefined) {
|
||||
return true
|
||||
}
|
||||
|
||||
return !!this.designerConfig['eventCollapse']
|
||||
},
|
||||
|
||||
hasPropEditor(propName, editorName) {
|
||||
if (!editorName) {
|
||||
return false
|
||||
|
@ -215,6 +226,23 @@
|
|||
return !!this.$root.$options.components[ownPropEditorName] ? ownPropEditorName : editorName //全局注册的属性编辑器组件
|
||||
},
|
||||
|
||||
showCollapse(propsObj) {
|
||||
let result = false
|
||||
|
||||
for (let propName in propsObj) {
|
||||
if (!propsObj.hasOwnProperty(propName)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (this.hasPropEditor(propName, propsObj[propName])) {
|
||||
result = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
},
|
||||
|
||||
editEventHandler(eventName, eventParams) {
|
||||
this.curEventName = eventName
|
||||
this.eventHeader = `${this.optionModel.name}.${eventName}(${eventParams.join(', ')}) {`
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-form-item :label="i18nt('designer.setting.gridColHeight')">
|
||||
<el-input type="number" v-model="optionModel.colHeight" @input.native="inputNumberHandler"
|
||||
min="0" class="hide-spin-button"></el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import i18n from "@/utils/i18n"
|
||||
import propertyMixin from "@/components/form-designer/setting-panel/property-editor/propertyMixin"
|
||||
|
||||
export default {
|
||||
name: "colHeight-editor",
|
||||
mixins: [i18n, propertyMixin],
|
||||
props: {
|
||||
designer: Object,
|
||||
selectedWidget: Object,
|
||||
optionModel: Object,
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -1,7 +1,9 @@
|
|||
<template>
|
||||
<el-input-number v-model="optionModel.defaultValue" :min="0" :max="optionModel.max" style="width: 100%"
|
||||
@change="emitDefaultValueChange">
|
||||
</el-input-number>
|
||||
<el-form-item :label="i18nt('designer.setting.defaultValue')">
|
||||
<el-input-number v-model="optionModel.defaultValue" :min="0" :max="optionModel.max" style="width: 100%"
|
||||
@change="emitDefaultValueChange">
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -57,6 +57,7 @@ const COMMON_PROPERTIES = {
|
|||
'showRowNumber' : 'showRowNumber-editor',
|
||||
'cellWidth' : 'cellWidth-editor',
|
||||
'cellHeight' : 'cellHeight-editor',
|
||||
'colHeight' : 'colHeight-editor',
|
||||
'gutter' : 'gutter-editor',
|
||||
'responsive' : 'responsive-editor',
|
||||
'span' : 'span-editor',
|
||||
|
|
|
@ -13,15 +13,30 @@
|
|||
<el-button :type="layoutType === 'H5' ? 'info': ''" @click="changeLayoutType('H5')">
|
||||
{{i18nt('designer.toolbar.mobileLayout')}}</el-button>
|
||||
</el-button-group>
|
||||
<el-button type="" style="margin-left: 20px" :title="i18nt('designer.toolbar.nodeTreeHint')" @click="showNodeTreeDrawer">
|
||||
<svg-icon icon-class="node-tree" /></el-button>
|
||||
</div>
|
||||
|
||||
<el-drawer :title="i18nt('designer.toolbar.nodeTreeTitle')" direction="ltr" :visible.sync="showNodeTreeDrawerFlag" :modal="false" :size="280"
|
||||
:destroy-on-close="true" class="node-tree-drawer">
|
||||
<el-tree ref="nodeTree" :data="nodeTreeData" node-key="id" default-expand-all highlight-current class="node-tree"
|
||||
icon-class="el-icon-arrow-right" @node-click="onNodeTreeClick"></el-tree>
|
||||
</el-drawer>
|
||||
|
||||
<div class="right-toolbar">
|
||||
<el-button type="text" @click="clearFormWidget"><i class="el-icon-delete" />{{i18nt('designer.toolbar.clear')}}</el-button>
|
||||
<el-button type="text" @click="previewForm"><i class="el-icon-view" />{{i18nt('designer.toolbar.preview')}}</el-button>
|
||||
<el-button type="text" @click="importJson">{{i18nt('designer.toolbar.importJson')}}</el-button>
|
||||
<el-button type="text" @click="exportJson">{{i18nt('designer.toolbar.exportJson')}}</el-button>
|
||||
<el-button type="text" @click="exportCode">{{i18nt('designer.toolbar.exportCode')}}</el-button>
|
||||
<el-button type="text" @click="generateSFC"><svg-icon icon-class="vue-sfc" />{{i18nt('designer.toolbar.generateSFC')}}</el-button>
|
||||
<el-button v-if="showToolButton('clearDesignerButton')" type="text" @click="clearFormWidget">
|
||||
<i class="el-icon-delete" />{{i18nt('designer.toolbar.clear')}}</el-button>
|
||||
<el-button v-if="showToolButton('previewFormButton')" type="text" @click="previewForm">
|
||||
<i class="el-icon-view" />{{i18nt('designer.toolbar.preview')}}</el-button>
|
||||
<el-button v-if="showToolButton('importJsonButton')" type="text" @click="importJson">
|
||||
{{i18nt('designer.toolbar.importJson')}}</el-button>
|
||||
<el-button v-if="showToolButton('exportJsonButton')" type="text" @click="exportJson">
|
||||
{{i18nt('designer.toolbar.exportJson')}}</el-button>
|
||||
<el-button v-if="showToolButton('exportCodeButton')" type="text" @click="exportCode">
|
||||
{{i18nt('designer.toolbar.exportCode')}}</el-button>
|
||||
<el-button v-if="showToolButton('generateSFCButton')" type="text" @click="generateSFC">
|
||||
<svg-icon icon-class="vue-sfc" />{{i18nt('designer.toolbar.generateSFC')}}</el-button>
|
||||
<slot name="toolButton"></slot>
|
||||
</div>
|
||||
|
||||
<el-dialog :title="i18nt('designer.toolbar.preview')" :visible.sync="showPreviewDialogFlag" v-if="showPreviewDialogFlag"
|
||||
|
@ -29,7 +44,8 @@
|
|||
:destroy-on-close="true" class="small-padding-dialog" width="75%" :fullscreen="layoutType === 'H5'">
|
||||
<div>
|
||||
<div class="form-render-wrapper" :class="[layoutType === 'H5' ? 'h5-layout' : '']">
|
||||
<VFormRender ref="preForm" :form-json="formJson" :form-data="testFormData"
|
||||
<VFormRender ref="preForm" :form-json="formJson" :form-data="testFormData" :preview-state="true"
|
||||
:option-data="testOptionData"
|
||||
@appendButtonClick="testOnAppendButtonClick" @buttonClick="testOnButtonClick"
|
||||
@formChange="handleFormChange"></VFormRender>
|
||||
</div>
|
||||
|
@ -138,12 +154,19 @@
|
|||
import VFormRender from '@/components/form-render/index'
|
||||
import CodeEditor from '@/components/code-editor/index'
|
||||
import Clipboard from 'clipboard'
|
||||
import {deepClone, copyToClipboard, generateId, getQueryParam} from "@/utils/util";
|
||||
import {
|
||||
deepClone,
|
||||
copyToClipboard,
|
||||
generateId,
|
||||
getQueryParam,
|
||||
traverseAllWidgets
|
||||
} from "@/utils/util";
|
||||
import i18n from '@/utils/i18n'
|
||||
import {generateCode} from "@/utils/code-generator";
|
||||
import {genSFC} from "@/utils/sfc-generator";
|
||||
import loadBeautifier from "@/utils/beautifierLoader";
|
||||
import { saveAs } from 'file-saver'
|
||||
import axios from "axios"
|
||||
|
||||
export default {
|
||||
name: "ToolbarPanel",
|
||||
|
@ -156,14 +179,20 @@
|
|||
props: {
|
||||
designer: Object
|
||||
},
|
||||
inject: ['getDesignerConfig'],
|
||||
data() {
|
||||
return {
|
||||
designerConfig: this.getDesignerConfig(),
|
||||
|
||||
showPreviewDialogFlag: false,
|
||||
showImportJsonDialogFlag: false,
|
||||
showExportJsonDialogFlag: false,
|
||||
showExportCodeDialogFlag: false,
|
||||
showFormDataDialogFlag: false,
|
||||
showExportSFCDialogFlag: false,
|
||||
showNodeTreeDrawerFlag: false,
|
||||
|
||||
nodeTreeData: [],
|
||||
|
||||
testFunc: '',
|
||||
importTemplate: '',
|
||||
|
@ -188,7 +217,17 @@
|
|||
// {'pName': 'iPhone12', 'pNum': 10},
|
||||
// {'pName': 'P50', 'pNum': 16},
|
||||
// ]
|
||||
|
||||
'select62173': 2,
|
||||
},
|
||||
testOptionData: {
|
||||
'select62173': [
|
||||
{label: '01', value: 1},
|
||||
{label: '22', value: 2},
|
||||
{label: '333', value: 3},
|
||||
]
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -211,8 +250,122 @@
|
|||
return this.designer.getLayoutType()
|
||||
},
|
||||
|
||||
},
|
||||
watch: {
|
||||
'designer.widgetList': {
|
||||
deep: true,
|
||||
handler(val) {
|
||||
//console.log('test-----', val)
|
||||
//this.refreshNodeTree()
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
methods: {
|
||||
showToolButton(configName) {
|
||||
if (this.designerConfig[configName] === undefined) {
|
||||
return true
|
||||
}
|
||||
|
||||
return !!this.designerConfig[configName]
|
||||
},
|
||||
|
||||
buildTreeNodeOfWidget(widget, treeNode) {
|
||||
let curNode = {
|
||||
id: widget.id,
|
||||
label: widget.options.label || widget.type,
|
||||
//selectable: true,
|
||||
}
|
||||
treeNode.push(curNode)
|
||||
|
||||
if (widget.category === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
curNode.children = []
|
||||
if (widget.type === 'grid') {
|
||||
widget.cols.map(col => {
|
||||
let colNode = {
|
||||
id: col.id,
|
||||
label: col.options.name || widget.type,
|
||||
children: []
|
||||
}
|
||||
curNode.children.push(colNode)
|
||||
col.widgetList.map(wChild => {
|
||||
this.buildTreeNodeOfWidget(wChild, colNode.children)
|
||||
})
|
||||
})
|
||||
} else if (widget.type === 'table') {
|
||||
//TODO: 需要考虑合并单元格!!
|
||||
widget.rows.map(row => {
|
||||
let rowNode = {
|
||||
id: row.id,
|
||||
label: 'table-row',
|
||||
selectable: false,
|
||||
children: [],
|
||||
}
|
||||
curNode.children.push(rowNode)
|
||||
|
||||
row.cols.map(cell => {
|
||||
if (!!cell.merged) { //跳过合并单元格!!
|
||||
return
|
||||
}
|
||||
|
||||
let rowChildren = rowNode.children
|
||||
let cellNode = {
|
||||
id: cell.id,
|
||||
label: 'table-cell',
|
||||
children: []
|
||||
}
|
||||
rowChildren.push(cellNode)
|
||||
|
||||
cell.widgetList.map(wChild => {
|
||||
this.buildTreeNodeOfWidget(wChild, cellNode.children)
|
||||
})
|
||||
})
|
||||
})
|
||||
} else if (widget.type === 'tab') {
|
||||
widget.tabs.map(tab => {
|
||||
let tabNode = {
|
||||
id: tab.id,
|
||||
label: tab.options.name || widget.type,
|
||||
selectable: false,
|
||||
children: []
|
||||
}
|
||||
curNode.children.push(tabNode)
|
||||
tab.widgetList.map(wChild => {
|
||||
this.buildTreeNodeOfWidget(wChild, tabNode.children)
|
||||
})
|
||||
})
|
||||
} else if (widget.type === 'sub-form') {
|
||||
widget.widgetList.map(wChild => {
|
||||
this.buildTreeNodeOfWidget(wChild, curNode.children)
|
||||
})
|
||||
} else if (widget.category === 'container') { //自定义容器
|
||||
widget.widgetList.map(wChild => {
|
||||
this.buildTreeNodeOfWidget(wChild, curNode.children)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
refreshNodeTree() {
|
||||
this.nodeTreeData.length = 0
|
||||
this.designer.widgetList.forEach(wItem => {
|
||||
this.buildTreeNodeOfWidget(wItem, this.nodeTreeData)
|
||||
})
|
||||
},
|
||||
|
||||
showNodeTreeDrawer() {
|
||||
this.refreshNodeTree()
|
||||
this.showNodeTreeDrawerFlag = true
|
||||
this.$nextTick(() => {
|
||||
if (!!this.designer.selectedId) { //同步当前选中组件到节点树!!!
|
||||
this.$refs.nodeTree.setCurrentKey(this.designer.selectedId)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
undoHistory() {
|
||||
this.designer.undoHistoryStep()
|
||||
},
|
||||
|
@ -405,12 +558,14 @@
|
|||
},
|
||||
|
||||
handleFormChange(fieldName, newValue, oldValue, formModel) {
|
||||
/*
|
||||
console.log('---formChange start---')
|
||||
console.log('fieldName', fieldName)
|
||||
console.log('newValue', newValue)
|
||||
console.log('oldValue', oldValue)
|
||||
console.log('formModel', formModel)
|
||||
console.log('---formChange end---')
|
||||
*/
|
||||
},
|
||||
|
||||
testOnAppendButtonClick(clickedWidget) {
|
||||
|
@ -421,6 +576,31 @@
|
|||
console.log('test', button)
|
||||
},
|
||||
|
||||
findWidgetById(wId) {
|
||||
let foundW = null
|
||||
traverseAllWidgets(this.designer.widgetList, (w) => {
|
||||
if (w.id === wId) {
|
||||
foundW = w
|
||||
}
|
||||
})
|
||||
|
||||
return foundW
|
||||
},
|
||||
|
||||
onNodeTreeClick(nodeData, node, nodeEl) {
|
||||
//console.log('test', JSON.stringify(nodeData))
|
||||
|
||||
if ((nodeData.selectable !== undefined) && !nodeData.selectable) {
|
||||
this.$message.info(this.i18nt('designer.hint.currentNodeCannotBeSelected'))
|
||||
} else {
|
||||
const selectedId = nodeData.id
|
||||
const foundW = this.findWidgetById(selectedId)
|
||||
if (!!foundW) {
|
||||
this.designer.setSelected(foundW)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -496,4 +676,106 @@
|
|||
box-shadow: 0 0 1px 10px #495060;
|
||||
height: calc(100vh - 142px);
|
||||
}
|
||||
|
||||
.node-tree-drawer ::v-deep {
|
||||
.el-drawer {
|
||||
padding: 15px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.el-drawer__header {
|
||||
margin-bottom: 12px;
|
||||
padding: 5px 5px 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*.node-tree-scroll-bar {*/
|
||||
/* height: 100%;*/
|
||||
/* overflow: auto;*/
|
||||
/*}*/
|
||||
|
||||
.node-tree ::v-deep {
|
||||
.el-tree > .el-tree-node:after {
|
||||
border-top: none;
|
||||
}
|
||||
.el-tree-node {
|
||||
position: relative;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.el-tree-node__content {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
.el-tree-node__expand-icon.is-leaf{
|
||||
display: none;
|
||||
}
|
||||
.el-tree-node__children {
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.el-tree-node :last-child:before {
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.el-tree > .el-tree-node:before {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.el-tree > .el-tree-node:after {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.el-tree-node:before {
|
||||
content: "";
|
||||
left: -4px;
|
||||
position: absolute;
|
||||
right: auto;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.el-tree-node:after {
|
||||
content: "";
|
||||
left: -4px;
|
||||
position: absolute;
|
||||
right: auto;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.el-tree-node:before {
|
||||
border-left: 1px dashed #4386c6;
|
||||
bottom: 0px;
|
||||
height: 100%;
|
||||
top: -26px;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
.el-tree-node:after {
|
||||
border-top: 1px dashed #4386c6;
|
||||
height: 20px;
|
||||
top: 12px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.el-tree-node.is-current > .el-tree-node__content {
|
||||
background: #c2d6ea !important;
|
||||
}
|
||||
|
||||
.el-tree-node__expand-icon {
|
||||
margin-left: -3px;
|
||||
padding: 6px 6px 6px 0px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.el-tree-node__expand-icon.el-icon-caret-right:before {
|
||||
//font-size: 16px;
|
||||
//content: "\e723";
|
||||
}
|
||||
|
||||
.el-tree-node__expand-icon.expanded.el-icon-caret-right:before {
|
||||
//font-size: 16px;
|
||||
//content: "\e722";
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -55,14 +55,14 @@
|
|||
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane name="formLib" style="padding: 8px">
|
||||
<el-tab-pane v-if="showFormTemplates()" name="formLib" style="padding: 8px">
|
||||
<span slot="label"><i class="el-icon-c-scale-to-original"></i> {{i18nt('designer.formLib')}}</span>
|
||||
|
||||
<template v-for="(ft, idx) in formTemplates">
|
||||
<el-card :bord-style="{ padding: '0' }" shadow="hover" class="ft-card">
|
||||
<el-popover placement="right" trigger="hover">
|
||||
<img slot="reference" :src="ft.imgUrl" style="width: 200px">
|
||||
<img :src="ft.imgUrl" style="height: 600px;width: 720px">
|
||||
<img slot="reference" :src="ftImages[idx].imgUrl" style="width: 200px">
|
||||
<img :src="ftImages[idx].imgUrl" style="height: 600px;width: 720px">
|
||||
</el-popover>
|
||||
<div class="bottom clear-fix">
|
||||
<span class="ft-title">#{{idx+1}} {{ft.title}}</span>
|
||||
|
@ -87,6 +87,15 @@
|
|||
import i18n from "@/utils/i18n"
|
||||
import axios from "axios"
|
||||
|
||||
import ftImg1 from '@/assets/ft-images/t1.png'
|
||||
import ftImg2 from '@/assets/ft-images/t2.png'
|
||||
import ftImg3 from '@/assets/ft-images/t3.png'
|
||||
import ftImg4 from '@/assets/ft-images/t4.png'
|
||||
import ftImg5 from '@/assets/ft-images/t5.png'
|
||||
import ftImg6 from '@/assets/ft-images/t6.png'
|
||||
import ftImg7 from '@/assets/ft-images/t7.png'
|
||||
import ftImg8 from '@/assets/ft-images/t8.png'
|
||||
|
||||
export default {
|
||||
name: "FieldPanel",
|
||||
mixins: [i18n],
|
||||
|
@ -96,8 +105,11 @@
|
|||
props: {
|
||||
designer: Object,
|
||||
},
|
||||
inject: ['getBannedWidgets', 'getDesignerConfig'],
|
||||
data() {
|
||||
return {
|
||||
designerConfig: this.getDesignerConfig(),
|
||||
|
||||
firstTab: 'componentLib',
|
||||
|
||||
scrollerHeight: 0,
|
||||
|
@ -110,6 +122,16 @@
|
|||
customFields,
|
||||
|
||||
formTemplates: formTemplates,
|
||||
ftImages: [
|
||||
{imgUrl: ftImg1},
|
||||
{imgUrl: ftImg2},
|
||||
{imgUrl: ftImg3},
|
||||
{imgUrl: ftImg4},
|
||||
{imgUrl: ftImg5},
|
||||
{imgUrl: ftImg6},
|
||||
{imgUrl: ftImg7},
|
||||
{imgUrl: ftImg8},
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -127,6 +149,18 @@
|
|||
})
|
||||
},
|
||||
methods: {
|
||||
isBanned(wName) {
|
||||
return this.getBannedWidgets().indexOf(wName) > -1
|
||||
},
|
||||
|
||||
showFormTemplates() {
|
||||
if (this.designerConfig['formTemplates'] === undefined) {
|
||||
return true
|
||||
}
|
||||
|
||||
return !!this.designerConfig['formTemplates']
|
||||
},
|
||||
|
||||
loadWidgets() {
|
||||
this.containers = this.containers.map(con => {
|
||||
return {
|
||||
|
@ -134,7 +168,7 @@
|
|||
displayName: this.i18n2t(`designer.widgetLabel.${con.type}`, `extension.widgetLabel.${con.type}`)
|
||||
}
|
||||
}).filter(con => {
|
||||
return !con.internal
|
||||
return !con.internal && !this.isBanned(con.type)
|
||||
})
|
||||
|
||||
this.basicFields = this.basicFields.map(fld => {
|
||||
|
@ -142,6 +176,8 @@
|
|||
...fld,
|
||||
displayName: this.i18n2t(`designer.widgetLabel.${fld.type}`, `extension.widgetLabel.${fld.type}`)
|
||||
}
|
||||
}).filter(fld => {
|
||||
return !this.isBanned(fld.type)
|
||||
})
|
||||
|
||||
this.advancedFields = this.advancedFields.map(fld => {
|
||||
|
@ -149,6 +185,8 @@
|
|||
...fld,
|
||||
displayName: this.i18n2t(`designer.widgetLabel.${fld.type}`, `extension.widgetLabel.${fld.type}`)
|
||||
}
|
||||
}).filter(fld => {
|
||||
return !this.isBanned(fld.type)
|
||||
})
|
||||
|
||||
this.customFields = this.customFields.map(fld => {
|
||||
|
@ -156,6 +194,8 @@
|
|||
...fld,
|
||||
displayName: this.i18n2t(`designer.widgetLabel.${fld.type}`, `extension.widgetLabel.${fld.type}`)
|
||||
}
|
||||
}).filter(fld => {
|
||||
return !this.isBanned(fld.type)
|
||||
})
|
||||
},
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ export const containers = [
|
|||
name: '',
|
||||
hidden: false,
|
||||
gutter: 12,
|
||||
colHeight: null, //栅格列统一高度属性,用于解决栅格列设置响应式布局浮动后被挂住的问题!!
|
||||
customClass: '', //自定义css类名
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<el-col class="grid-cell" :class="[customClass]" v-bind="layoutProps"
|
||||
<el-col class="grid-cell" :class="[customClass]" v-bind="layoutProps" :style="colHeightStyle"
|
||||
:key="widget.id" v-show="!widget.options.hidden">
|
||||
<template v-if="!!widget.widgetList && (widget.widgetList.length > 0)">
|
||||
<template v-for="(subWidget, swIdx) in widget.widgetList">
|
||||
|
@ -38,6 +38,12 @@
|
|||
parentWidget: Object,
|
||||
parentList: Array,
|
||||
indexOfParentList: Number,
|
||||
|
||||
colHeight: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
|
||||
},
|
||||
inject: ['refList', 'globalModel', 'formConfig', 'previewState'],
|
||||
data() {
|
||||
|
@ -58,6 +64,10 @@
|
|||
return this.widget.options.customClass || ''
|
||||
},
|
||||
|
||||
colHeightStyle() {
|
||||
return !!this.colHeight ? {height: this.colHeight + 'px'} : {}
|
||||
},
|
||||
|
||||
},
|
||||
created() {
|
||||
this.initLayoutProps()
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
:ref="widget.id" v-show="!widget.options.hidden">
|
||||
<template v-for="(colWidget, colIdx) in widget.cols">
|
||||
<grid-col-item :widget="colWidget" :key="colIdx" :parent-list="widget.cols"
|
||||
:index-of-parent-list="colIdx" :parent-widget="widget"></grid-col-item>
|
||||
:index-of-parent-list="colIdx" :parent-widget="widget"
|
||||
:col-height="widget.options.colHeight"></grid-col-item>
|
||||
</template>
|
||||
</el-row>
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
sfRefList: this.subFormRefList, //收集SubForm引用
|
||||
formConfig: this.formConfig,
|
||||
globalOptionData: this.optionData,
|
||||
getOptionData: () => this.optionData, /* 该方法用于在异步更新option-data之后重新获取到最新值 */
|
||||
globalModel: {
|
||||
formModel: this.formDataModel,
|
||||
},
|
||||
|
@ -356,13 +357,15 @@
|
|||
* @param widgetNames 指定重新加载的组件名称或组件名数组,不传则重新加载所有选项字段
|
||||
*/
|
||||
reloadOptionData(widgetNames) {
|
||||
//this._provided.globalOptionData = this.optionData
|
||||
|
||||
let eventParams = []
|
||||
if (!!widgetNames && (typeof widgetNames === 'string')) {
|
||||
eventParams = [widgetNames]
|
||||
} else if (!!widgetNames && Array.isArray(widgetNames)) {
|
||||
eventParams = [...widgetNames]
|
||||
}
|
||||
this.broadcast('FieldWidget', 'reloadOptions', [eventParams])
|
||||
this.broadcast('FieldWidget', 'reloadOptionItems', [eventParams])
|
||||
},
|
||||
|
||||
getFormData(needValidation = true) {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1637920503900" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4875" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M332.48 500.864a25.6 25.6 0 1 0 0-51.2H192.384v-184.96a115.2 115.2 0 0 0 89.6-112.128c0-63.488-51.712-115.2-115.2-115.2s-115.2 51.712-115.2 115.2a115.2 115.2 0 0 0 89.6 112.128v696.192a25.6 25.6 0 1 0 51.2 0v-141.12c2.304 0.192 4.48 0.512 6.912 0.512h133.184a25.6 25.6 0 1 0 0-51.2H199.296c-3.456 0-5.504-0.448-6.08-0.256a29.184 29.184 0 0 1-0.896-8.576V500.8h140.16zM102.784 152.64c0-35.264 28.736-64 64-64s64 28.736 64 64-28.736 64-64 64-64-28.736-64-64zM921.216 360.064h-486.4c-28.224 0-51.2 22.976-51.2 51.2v128c0 28.224 22.976 51.2 51.2 51.2h486.4c28.224 0 51.2-22.976 51.2-51.2v-128c0-28.224-22.976-51.2-51.2-51.2z m-486.336 179.2v-128h486.4v128h-486.4zM921.216 679.616h-486.4c-28.224 0-51.2 22.976-51.2 51.2v128c0 28.224 22.976 51.2 51.2 51.2h486.4c28.224 0 51.2-22.976 51.2-51.2v-128c0-28.224-22.976-51.2-51.2-51.2z m-486.336 179.2v-128h486.4v128h-486.4z" p-id="4876"></path></svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -112,6 +112,7 @@ export default {
|
|||
loadFormTemplateHint: 'Are you sure to load this template?',
|
||||
loadFormTemplateSuccess: 'Load form template success!',
|
||||
loadFormTemplateFailed: 'Load form template failed.',
|
||||
currentNodeCannotBeSelected: 'The current node cannot be selected.',
|
||||
|
||||
widgetSetting: 'Widget Config',
|
||||
formSetting: 'Form Config',
|
||||
|
@ -147,6 +148,8 @@ export default {
|
|||
pcLayout: 'PC',
|
||||
padLayout: 'Pad',
|
||||
mobileLayout: 'H5',
|
||||
nodeTreeHint: 'Tree View Of Component Hierarchy',
|
||||
nodeTreeTitle: 'Tree View Of Component Hierarchy',
|
||||
clear: 'Clear',
|
||||
preview: 'Preview',
|
||||
importJson: 'Import JSON',
|
||||
|
@ -223,6 +226,7 @@ export default {
|
|||
|
||||
cellWidth: 'Width',
|
||||
cellHeight: 'Height',
|
||||
gridColHeight: 'Height Of Col(px)',
|
||||
gutter: 'Gutter(px)',
|
||||
columnSetting: 'Cols Setting',
|
||||
colsOfGrid: 'Cols Of Grid:',
|
||||
|
|
|
@ -112,6 +112,7 @@ export default {
|
|||
loadFormTemplateHint: '是否加载这个模板?加载后会覆盖设计器当前表单,你可以使用“撤销”功能恢复。',
|
||||
loadFormTemplateSuccess: '表单模板加载成功',
|
||||
loadFormTemplateFailed: '表单模板加载失败',
|
||||
currentNodeCannotBeSelected: '当前组件节点不可选择',
|
||||
|
||||
widgetSetting: '组件设置',
|
||||
formSetting: '表单设置',
|
||||
|
@ -147,6 +148,8 @@ export default {
|
|||
pcLayout: 'PC',
|
||||
padLayout: 'Pad',
|
||||
mobileLayout: 'H5',
|
||||
nodeTreeHint: '组件层次结构树',
|
||||
nodeTreeTitle: '组件层次结构树',
|
||||
clear: '清空',
|
||||
preview: '预览',
|
||||
importJson: '导入JSON',
|
||||
|
@ -223,7 +226,8 @@ export default {
|
|||
|
||||
cellWidth: '宽度',
|
||||
cellHeight: '高度',
|
||||
gutter: '栅格间隔(像素)',
|
||||
gridColHeight: '栅格列统一高度(px)',
|
||||
gutter: '栅格间隔(px)',
|
||||
columnSetting: '栅格属性设置',
|
||||
colsOfGrid: '当前栅格列:',
|
||||
colSpanTitle: '栅格宽度',
|
||||
|
|
|
@ -8,7 +8,7 @@ export const DESIGNER_OPTIONS = {
|
|||
|
||||
}
|
||||
|
||||
export const VARIANT_FORM_VERSION = '2.1.7'
|
||||
export const VARIANT_FORM_VERSION = '2.1.8'
|
||||
|
||||
//export const MOCK_CASE_URL = 'https://www.fastmock.site/mock/2de212e0dc4b8e0885fea44ab9f2e1d0/vform/'
|
||||
export const MOCK_CASE_URL = 'https://ks3-cn-beijing.ksyuncs.com/vform-static/vcase/'
|
||||
|
|
|
@ -172,6 +172,34 @@ export function traverseContainWidgets(widgetList, handler) {
|
|||
})
|
||||
}
|
||||
|
||||
export function traverseAllWidgets(widgetList, handler) {
|
||||
widgetList.map(w => {
|
||||
handler(w)
|
||||
|
||||
if (w.type === 'grid') {
|
||||
w.cols.map(col => {
|
||||
handler(col)
|
||||
traverseAllWidgets(col.widgetList, handler)
|
||||
})
|
||||
} else if (w.type === 'table') {
|
||||
w.rows.map(row => {
|
||||
row.cols.map(cell => {
|
||||
handler(cell)
|
||||
traverseAllWidgets(cell.widgetList, handler)
|
||||
})
|
||||
})
|
||||
} else if (w.type === 'tab') {
|
||||
w.tabs.map(tab => {
|
||||
traverseAllWidgets(tab.widgetList, handler)
|
||||
})
|
||||
} else if (w.type === 'sub-form') {
|
||||
traverseAllWidgets(w.widgetList, handler)
|
||||
} else if (w.category === 'container') { //自定义容器
|
||||
traverseAllWidgets(w.widgetList, handler)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function copyToClipboard(content, clickEvent, $message, successMsg, errorMsg) {
|
||||
const clipboard = new Clipboard(clickEvent.target, {
|
||||
text: () => content
|
||||
|
|