variant-form/src/components/form-render/index.vue

565 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!--
/**
* author: vformAdmin
* email: vdpadmin@163.com
* website: https://www.vform666.com
* date: 2021.08.18
* remark: 如果要分发VForm源码需在本文件顶部保留此文件头信息
*/
-->
<template>
<el-form :label-position="labelPosition" :size="size" :class="[customClass]" class="render-form"
:label-width="labelWidth" :validate-on-rule-change="false"
:model="formDataModel" ref="renderForm"
@submit.native.prevent>
<template v-for="(widget, index) in widgetList">
<template v-if="'container' === widget.category">
<component :is="getContainerWidgetName(widget)" :widget="widget" :key="widget.id" :parent-list="widgetList"
:index-of-parent-list="index" :parent-widget="null"></component>
</template>
<template v-else>
<component :is="getWidgetName(widget)" :field="widget" :form-model="formDataModel" :designer="null" :key="widget.id" :parent-list="widgetList"
:index-of-parent-list="index" :parent-widget="null"></component>
</template>
</template>
</el-form>
</template>
<script>
//import ElForm from 'element-ui/packages/form/src/form.vue' /* 用于源码调试Element UI */
import emitter from 'element-ui/lib/mixins/emitter'
import './container-item/index'
import FieldComponents from '@/components/form-designer/form-widget/field-widget/index'
import {deepClone, insertCustomCssToHead, insertGlobalFunctionsToHtml} from "../../utils/util"
import i18n, { changeLocale } from "../../utils/i18n"
export default {
name: "VFormRender",
componentName: 'VFormRender',
mixins: [emitter, i18n],
components: {
//ElForm,
...FieldComponents,
},
props: {
formJson: Object, //prop传入的表单JSON配置
formData: { //prop传入的表单数据
Object,
default: () => {}
},
optionData: { //prop传入的选项数据
type: Object,
default: () => {}
},
previewState: { //是否表单预览状态
type: Boolean,
default: false
}
},
provide() {
return {
refList: this.widgetRefList,
sfRefList: this.subFormRefList, //收集SubForm引用
formConfig: this.formConfig,
globalOptionData: this.optionData,
getOptionData: () => this.optionData, /* 该方法用于在异步更新option-data之后重新获取到最新值 */
globalModel: {
formModel: this.formDataModel,
},
previewState: this.previewState,
}
},
data() {
return {
formJsonObj: this.formJson,
formDataModel: {
//
},
widgetRefList: {},
subFormRefList: {},
}
},
computed: {
formConfig() {
return this.formJsonObj.formConfig
},
widgetList() {
return this.formJsonObj.widgetList
},
labelPosition() {
if (!!this.formConfig && !!this.formConfig.labelPosition) {
return this.formConfig.labelPosition
}
return 'left'
},
labelWidth() {
if (!!this.formConfig && !!this.formConfig.labelWidth) {
return this.formConfig.labelWidth + 'px'
}
return '80px'
},
size() {
if (!!this.formConfig && !!this.formConfig.size) {
return this.formConfig.size
}
return 'medium'
},
customClass() {
return !!this.formConfig && !!this.formConfig.customClass ? this.formConfig.customClass : ''
},
},
watch: {
//
},
created() {
this.buildFormModel(!this.formJsonObj ? null : this.formJsonObj.widgetList)
this.initFormObject()
},
mounted() {
this.initLocale()
this.handleOnMounted()
},
methods: {
initFormObject() {
this.insertCustomStyleAndScriptNode()
this.addFieldChangeEventHandler()
this.addFieldValidateEventHandler()
this.registerFormToRefList()
this.handleOnCreated()
},
getContainerWidgetName(widget) {
return widget.type + '-item'
},
getWidgetName(widget) {
return widget.type + '-widget'
},
initLocale() {
let curLocale = localStorage.getItem('v_form_locale') || 'zh-CN'
this.changeLanguage(curLocale)
},
insertCustomStyleAndScriptNode() {
if (!!this.formConfig && !!this.formConfig.cssCode) {
insertCustomCssToHead(this.formConfig.cssCode)
}
if (!!this.formConfig && !!this.formConfig.functions) {
insertGlobalFunctionsToHtml(this.formConfig.functions)
}
},
buildFormModel(widgetList) {
if (!!widgetList && (widgetList.length > 0)) {
widgetList.forEach((wItem) => {
this.buildDataFromWidget(wItem)
})
}
},
buildDataFromWidget(wItem) {
if (wItem.category === 'container') {
if (wItem.type === 'grid') {
if (!!wItem.cols && (wItem.cols.length > 0)) {
wItem.cols.forEach((childItem) => {
this.buildDataFromWidget(childItem)
})
}
} else if (wItem.type === 'table') {
if (!!wItem.rows && (wItem.rows.length > 0)) {
wItem.rows.forEach((rowItem) => {
if (!!rowItem.cols && (rowItem.cols.length > 0)) {
rowItem.cols.forEach((colItem) => {
this.buildDataFromWidget(colItem)
})
}
})
}
} else if (wItem.type === 'tab') {
if (!!wItem.tabs && (wItem.tabs.length > 0)) {
wItem.tabs.forEach((tabItem) => {
if (!!tabItem.widgetList && (tabItem.widgetList.length > 0)) {
tabItem.widgetList.forEach((childItem) => {
this.buildDataFromWidget(childItem)
})
}
})
}
} else if (wItem.type === 'sub-form') {
let subFormName = wItem.options.name
if (!this.formData.hasOwnProperty(subFormName)) {
let subFormDataRow = {}
if (wItem.options.showBlankRow) {
wItem.widgetList.forEach(subFormItem => {
if (!!subFormItem.formItemFlag) {
subFormDataRow[subFormItem.options.name] = subFormItem.options.defaultValue
}
})
this.$set(this.formDataModel, subFormName, [subFormDataRow]) //
} else {
this.$set(this.formDataModel, subFormName, []) //
}
} else {
let initialValue = this.formData[subFormName]
this.$set(this.formDataModel, subFormName, deepClone(initialValue))
}
} else if ((wItem.type === 'grid-col') || (wItem.type === 'table-cell')) {
if (!!wItem.widgetList && (wItem.widgetList.length > 0)) {
wItem.widgetList.forEach((childItem) => {
this.buildDataFromWidget(childItem)
})
}
} else { //自定义容器组件
if (!!wItem.widgetList && (wItem.widgetList.length > 0)) {
wItem.widgetList.forEach((childItem) => {
this.buildDataFromWidget(childItem)
})
}
}
} else if (!!wItem.formItemFlag) {
if (!this.formData.hasOwnProperty(wItem.options.name)) {
//this.formDataModel[wItem.options.name] = '' //这种写法不支持对象属性响应式更新,必须用$set方法
this.$set(this.formDataModel, wItem.options.name, wItem.options.defaultValue) //设置字段默认值
} else {
let initialValue = this.formData[wItem.options.name]
this.$set(this.formDataModel, wItem.options.name, deepClone(initialValue))
}
}
},
addFieldChangeEventHandler() {
this.$off('fieldChange') //移除原有事件监听
this.$on('fieldChange', function (fieldName, newValue, oldValue, subFormName, subFormRowIndex) {
this.handleFieldDataChange(fieldName, newValue, oldValue, subFormName, subFormRowIndex)
this.$emit('formChange', fieldName, newValue, oldValue, this.formDataModel, subFormName, subFormRowIndex)
})
},
addFieldValidateEventHandler() {
this.$off('fieldValidation') //移除原有事件监听
this.$on('fieldValidation', (fieldName) => {
this.$refs.renderForm.validateField(fieldName)
})
},
registerFormToRefList() {
this.widgetRefList['v_form_ref'] = this
},
handleFieldDataChange(fieldName, newValue, oldValue, subFormName, subFormRowIndex) {
if (!!this.formConfig && !!this.formConfig.onFormDataChange) {
let customFunc = new Function('fieldName', 'newValue', 'oldValue', 'formModel', 'subFormName', 'subFormRowIndex',
this.formConfig.onFormDataChange)
customFunc.call(this, fieldName, newValue, oldValue, this.formDataModel, subFormName, subFormRowIndex)
}
},
handleOnCreated() {
if (!!this.formConfig && !!this.formConfig.onFormCreated) {
let customFunc = new Function(this.formConfig.onFormCreated)
customFunc.call(this)
}
},
handleOnMounted() {
if (!!this.formConfig && !!this.formConfig.onFormMounted) {
let customFunc = new Function(this.formConfig.onFormMounted)
customFunc.call(this)
}
},
findWidgetAndSetDisabled(widgetName, disabledFlag) {
let foundW = this.getWidgetRef(widgetName)
if (!!foundW) {
foundW.setDisabled(disabledFlag)
}
},
findWidgetAndSetHidden(widgetName, hiddenFlag) {
let foundW = this.getWidgetRef(widgetName)
if (!!foundW) {
foundW.setHidden(hiddenFlag)
}
},
//--------------------- 以下为组件支持外部调用的API方法 begin ------------------//
/* 提示:用户可自行扩充这些方法!!! */
changeLanguage(langName) {
changeLocale(langName)
},
getNativeForm() { //获取原生form引用
return this.$refs['renderForm']
},
getWidgetRef(widgetName, showError = false) {
let foundRef = this.widgetRefList[widgetName]
if (!foundRef && !!showError) {
this.$message.error(this.i18nt('render.hint.refNotFound') + widgetName)
}
return foundRef
},
clearFormDataModel() {
for (let pkey in this.formDataModel) {
delete this.formDataModel[pkey]
}
},
/**
* 动态加载表单JSON
* @param newFormJson
*/
setFormJson(newFormJson) {
if (!!newFormJson) {
if ((typeof newFormJson === 'string') || (newFormJson.constructor === Object)) {
let newFormJsonObj = null
if (typeof newFormJson === 'string') {
newFormJsonObj = JSON.parse(newFormJson)
} else {
newFormJsonObj = newFormJson
}
if (!newFormJsonObj.formConfig || !newFormJsonObj.widgetList) {
this.$message.error('Invalid format of form json.')
return
}
/* formDataModel必须在widgetList赋值完成初始化因为widgetList赋值意味着子组件开始创建 */
//this.formDataModel = {} //清空表单数据对象有bug会导致表单校验失败
this.clearFormDataModel() //上行代码有问题,会导致表单校验失败,故保留原对象引用只清空对象属性!!
this.buildFormModel(newFormJsonObj.widgetList)
this.$set(this.formJsonObj, 'formConfig', newFormJsonObj.formConfig)
this._provided.formConfig = newFormJsonObj.formConfig //强制更新provide的formConfig对象
this.$set(this.formJsonObj, 'widgetList', newFormJsonObj.widgetList)
this.initFormObject()
this.handleOnMounted()
} else {
this.$message.error('Set form json failed.')
}
}
},
/**
* 重新加载选项数据
* @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', 'reloadOptionItems', [eventParams])
},
getFormData(needValidation = true) {
if (!needValidation) {
return this.formDataModel
}
let callback = function nullFunc() {}
let promise = new window.Promise(function (resolve, reject) {
callback = function(formData, error) {
!error ? resolve(formData) : reject(error);
};
});
this.$refs['renderForm'].validate((valid) => {
if (valid) {
callback(this.formDataModel)
} else {
callback(this.formDataModel, this.i18nt('render.hint.validationFailed'))
}
})
return promise
},
setFormData(formData) { //设置表单数据
//this.formDataModel = formData //inject注入的formModel不是响应式的直接赋值在其他组件拿不到最新值
Object.keys(this.formDataModel).forEach(propName => {
if (!!formData && formData.hasOwnProperty(propName)) {
this.formDataModel[propName] = deepClone( formData[propName] )
}
})
//this.formDataModel = formData
//this._provided.globalModel.formModel = formData /* 这种写法可使inject的属性保持响应式更新 */
//
// 通知SubForm组件表单数据更新事件
//this.broadcast('ContainerItem', 'setFormData', formData)
this.broadcast('ContainerItem', 'setFormData', this.formDataModel)
// 通知FieldWidget组件表单数据更新事件
//this.broadcast('FieldWidget', 'setFormData', formData)
this.broadcast('FieldWidget', 'setFormData', this.formDataModel)
},
getFieldValue(fieldName) { //单个字段获取值
let fieldRef = this.getWidgetRef(fieldName)
if (!!fieldRef && !!fieldRef.getValue) {
fieldRef.getValue()
}
},
setFieldValue(fieldName, fieldValue) { //单个更新字段值
let fieldRef = this.getWidgetRef(fieldName)
if (!!fieldRef && !!fieldRef.setValue) {
fieldRef.setValue(fieldValue)
}
},
getSubFormValues(subFormName, needValidation = true) {
let foundSFRef = this.subFormRefList[subFormName]
// if (!foundSFRef) {
// return this.formDataModel[subFormName]
// }
return foundSFRef.getSubFormValues(needValidation)
},
disableForm() {
let wNameList = Object.keys(this.widgetRefList)
wNameList.forEach(wName => {
let foundW = this.getWidgetRef(wName)
if (!!foundW) {
// if (!!foundW.setDisabled) {
// foundW.setDisabled(true)
// }
!!foundW.setDisabled && foundW.setDisabled(true)
}
})
},
enableForm() {
let wNameList = Object.keys(this.widgetRefList)
wNameList.forEach(wName => {
let foundW = this.getWidgetRef(wName)
if (!!foundW) {
// if (!!foundW.setDisabled) {
// foundW.setDisabled(false)
// }
!!foundW.setDisabled && foundW.setDisabled(false)
}
})
},
resetForm() { //重置表单
let subFormNames = Object.keys(this.subFormRefList)
subFormNames.forEach(sfName => {
if (!!this.subFormRefList[sfName].resetSubForm) {
this.subFormRefList[sfName].resetSubForm()
}
})
let wNameList = Object.keys(this.widgetRefList)
wNameList.forEach(wName => {
let foundW = this.getWidgetRef(wName)
if (!!foundW && !!foundW.resetField) {
foundW.resetField()
}
})
this.$nextTick(() => {
this.clearValidate() /* 清除resetField方法触发的校验错误提示 */
})
},
clearValidate(props) {
this.$refs.renderForm.clearValidate(props)
},
validateForm() {
//
},
validateFields() {
//
},
disableWidgets(widgetNames) {
if (!!widgetNames) {
if (typeof widgetNames === 'string') {
this.findWidgetAndSetDisabled(widgetNames, true)
} else if (Array.isArray(widgetNames)) {
widgetNames.forEach(wn => {
this.findWidgetAndSetDisabled(wn, true)
})
}
}
},
enableWidgets(widgetNames) {
if (!!widgetNames) {
if (typeof widgetNames === 'string') {
this.findWidgetAndSetDisabled(widgetNames, false)
} else if (Array.isArray(widgetNames)) {
widgetNames.forEach(wn => {
this.findWidgetAndSetDisabled(wn, false)
})
}
}
},
hideWidgets(widgetNames) {
if (!!widgetNames) {
if (typeof widgetNames === 'string') {
this.findWidgetAndSetHidden(widgetNames, true)
} else if (Array.isArray(widgetNames)) {
widgetNames.forEach(wn => {
this.findWidgetAndSetHidden(wn, true)
})
}
}
},
showWidgets(widgetNames) {
if (!!widgetNames) {
if (typeof widgetNames === 'string') {
this.findWidgetAndSetHidden(widgetNames, false)
} else if (Array.isArray(widgetNames)) {
widgetNames.forEach(wn => {
this.findWidgetAndSetHidden(wn, false)
})
}
}
}
//--------------------- 以上为组件支持外部调用的API方法 end ------------------//
},
}
</script>
<style lang="scss" scoped>
.el-form ::v-deep .el-row {
padding: 8px;
}
</style>