From 486ceafce1d728bc069da71238430aae4315d280 Mon Sep 17 00:00:00 2001 From: vdpAdmin Date: Tue, 8 Mar 2022 17:59:10 +0800 Subject: [PATCH] =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8D=87=E7=BA=A7=E5=88=B03.?= =?UTF-8?q?0.4=EF=BC=9A=201.=20=E6=96=B0=E5=A2=9E=E5=BF=85=E5=A1=AB?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E8=87=AA=E5=AE=9A=E4=B9=89=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E5=B1=9E=E6=80=A7requiredHint=EF=BC=9B=202.=20=E5=BD=93?= =?UTF-8?q?=E5=AE=B9=E5=99=A8=E8=A2=AB=E8=AE=BE=E7=BD=AE=E9=9A=90=E8=97=8F?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E5=90=8C=E6=AD=A5=E6=B8=85=E9=99=A4=E5=AE=B9?= =?UTF-8?q?=E5=99=A8=E5=86=85=E6=89=80=E6=9C=89=E5=AD=97=E6=AE=B5=E7=9A=84?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E8=A7=84=E5=88=99=EF=BC=9B=203.=20=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E5=99=A8=E3=80=81=E6=B8=B2=E6=9F=93=E5=99=A8=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E4=B8=A4=E4=B8=AAAPI=E6=96=B9=E6=B3=95=EF=BC=9AgetFie?= =?UTF-8?q?ldWidgets()=E3=80=81getContainerWidgets()=EF=BC=9B=204.=20field?= =?UTF-8?q?-list-api=E5=B1=9E=E6=80=A7=E5=85=81=E8=AE=B8=E4=BC=A0=E9=80=92?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E5=A4=B4=E4=BF=A1=E6=81=AF=EF=BC=9B=205.=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BC=82=E6=AD=A5=E8=AF=B7=E6=B1=82=E6=97=B6?= =?UTF-8?q?setFormData()=E5=87=BD=E6=95=B0=E5=8F=AF=E8=83=BD=E5=A4=B1?= =?UTF-8?q?=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=9B=206.=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=85=B6=E4=BB=96=E9=83=A8=E5=88=86bug=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- package.json | 2 +- .../form-widget/field-widget/fieldMixin.js | 15 +++- src/components/form-designer/index.vue | 22 ++++- .../property-editor/requiredHint-editor.vue | 24 ++++++ .../setting-panel/propertyRegister.js | 1 + .../form-designer/toolbar-panel/index.vue | 18 ++++ .../widget-panel/widgetsConfig.js | 13 +++ .../container-item/containerItemMixin.js | 27 +++++- src/components/form-render/index.vue | 21 ++++- src/extension/extension-loader.js | 2 +- src/lang/en-US.js | 1 + src/lang/zh-CN.js | 1 + src/utils/config.js | 2 +- src/utils/emitter.js | 24 +++++- src/utils/util.js | 83 +++++++++++++++++++ vite.config.js | 2 +- 17 files changed, 245 insertions(+), 15 deletions(-) create mode 100644 src/components/form-designer/setting-panel/property-editor/requiredHint-editor.vue diff --git a/README.md b/README.md index 8cd12b0..95db881 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Variant Form 3 For Vue 3.x #### 一款高效的Vue 3低代码表单,可视化设计,一键生成源码,享受更多摸鱼时间。 -![image](https://vform2021.oss-cn-beijing.aliyuncs.com/vform_demo.gif?versionId=CAEQGBiBgIDst4zj4hciIDQyYTkyOGY1ZGJiODQ4YTk5ZjkxMGIwMDY0MmY2M2Ri) +![image](https://ks3-cn-beijing.ksyuncs.com/vform-static/img/vform_demo.gif)
diff --git a/package.json b/package.json index 85f31ce..2b018f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "variant-form3", - "version": "3.0.3", + "version": "3.0.4", "private": false, "scripts": { "serve": "vite", diff --git a/src/components/form-designer/form-widget/field-widget/fieldMixin.js b/src/components/form-designer/form-widget/field-widget/fieldMixin.js index d22800b..ce66de6 100644 --- a/src/components/form-designer/form-widget/field-widget/fieldMixin.js +++ b/src/components/form-designer/form-widget/field-widget/fieldMixin.js @@ -34,6 +34,13 @@ export default { methods: { //--------------------- 组件内部方法 begin ------------------// + getPropName() { + if (this.subFormItemFlag && !this.designState) { + return this.subFormName + "." + this.subFormRowIndex + "." + this.field.options.name + "" + } else { + return this.field.options.name + } + }, initFieldModel() { if (!this.field.formItemFlag) { @@ -201,7 +208,7 @@ export default { required: true, //trigger: ['blur', 'change'], trigger: ['blur'], /* 去掉change事件触发校验,change事件触发时formModel数据尚未更新,导致radio/checkbox必填校验出错!! */ - message: this.i18nt('render.hint.fieldRequired'), + message: this.field.options.requiredHint || this.i18nt('render.hint.fieldRequired'), }) } @@ -320,8 +327,7 @@ export default { this.oldFieldValue = deepClone(value) /* oldFieldValue需要在initFieldModel()方法中赋初值!! */ /* 主动触发表单的单个字段校验,用于清除字段可能存在的校验错误提示 */ - this.dispatch('VFormRender', 'fieldValidation', [this.field.options.name]) - // eventBus.$emit('fieldValidation', [this.field.options.name]) + this.dispatch('VFormRender', 'fieldValidation', [this.getPropName()]) }, handleFocusCustomEvent(event) { @@ -343,6 +349,9 @@ export default { handleInputCustomEvent(value) { this.syncUpdateFormModel(value) + /* 主动触发表单的单个字段校验,用于清除字段可能存在的校验错误提示 */ + this.dispatch('VFormRender', 'fieldValidation', [this.getPropName()]) + if (!!this.field.options.onInput) { let customFn = new Function('value', this.field.options.onInput) customFn.call(this, value) diff --git a/src/components/form-designer/index.vue b/src/components/form-designer/index.vue index a6f0b27..61dfd76 100644 --- a/src/components/form-designer/index.vue +++ b/src/components/form-designer/index.vue @@ -68,7 +68,8 @@ import SettingPanel from './setting-panel/index' import VFormWidget from './form-widget/index' import {createDesigner} from "@/components/form-designer/designer" - import {addWindowResizeHandler, deepClone, getQueryParam} from "@/utils/util" + import {addWindowResizeHandler, deepClone, getQueryParam, getAllContainerWidgets, + getAllFieldWidgets} from "@/utils/util" import {MOCK_CASE_URL, VARIANT_FORM_VERSION} from "@/utils/config" import i18n, { changeLocale } from "@/utils/i18n" import axios from 'axios' @@ -243,7 +244,8 @@ return } - axios.get(this.fieldListApi.URL).then(res => { + let headers = this.fieldListApi.headers || {} + axios.get(this.fieldListApi.URL, {'headers': headers}).then(res => { let labelKey = this.fieldListApi.labelKey || 'label' let nameKey = this.fieldListApi.nameKey || 'name' @@ -340,6 +342,22 @@ this.$refs.toolbarRef.generateSFC() }, + /** + * 获取所有字段组件 + * @returns {*[]} + */ + getFieldWidgets() { + return getAllFieldWidgets(this.designer.widgetList) + }, + + /** + * 获取所有容器组件 + * @returns {*[]} + */ + getContainerWidgets() { + return getAllContainerWidgets(this.designer.widgetList) + }, + //TODO: 增加更多方法!! } diff --git a/src/components/form-designer/setting-panel/property-editor/requiredHint-editor.vue b/src/components/form-designer/setting-panel/property-editor/requiredHint-editor.vue new file mode 100644 index 0000000..d44c442 --- /dev/null +++ b/src/components/form-designer/setting-panel/property-editor/requiredHint-editor.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/form-designer/setting-panel/propertyRegister.js b/src/components/form-designer/setting-panel/propertyRegister.js index f653cd9..303b439 100644 --- a/src/components/form-designer/setting-panel/propertyRegister.js +++ b/src/components/form-designer/setting-panel/propertyRegister.js @@ -24,6 +24,7 @@ const COMMON_PROPERTIES = { 'labelHidden' : 'labelHidden-editor', 'rows' : 'rows-editor', 'required' : 'required-editor', + 'requiredHint' : 'requiredHint-editor', 'validation' : 'validation-editor', 'validationHint' : 'validationHint-editor', 'readonly' : 'readonly-editor', diff --git a/src/components/form-designer/toolbar-panel/index.vue b/src/components/form-designer/toolbar-panel/index.vue index 7ec3b1c..26cc26d 100644 --- a/src/components/form-designer/toolbar-panel/index.vue +++ b/src/components/form-designer/toolbar-panel/index.vue @@ -62,6 +62,7 @@ {{i18nt('designer.hint.disableForm')}} {{i18nt('designer.hint.enableForm')}} {{i18nt('designer.hint.closePreview')}} + Test Load @@ -594,6 +595,23 @@ this.$refs['preForm'].enableForm() }, + testLoadForm() { + axios.get('https://www.fastmock.site/mock/e9710039bb5f11262d1a0f2f0bbe08c8/vform3/getFS').then(res => { + let newFormJson = res.data + this.$refs.preForm.setFormJson(newFormJson) + // let newFormData = {'input30696': '668899'} + // this.$refs.preForm.setFormData(newFormData) + + console.log('test', 'aaaaaaaa') + this.$nextTick(() => { + let newFormData = {'input30696': '668899'} + this.$refs.preForm.setFormData(newFormData) + }) + }).catch(err => { + // + }) + }, + handleFormChange(fieldName, newValue, oldValue, formModel) { /* console.log('---formChange start---') diff --git a/src/components/form-designer/widget-panel/widgetsConfig.js b/src/components/form-designer/widget-panel/widgetsConfig.js index c2785f5..3783645 100644 --- a/src/components/form-designer/widget-panel/widgetsConfig.js +++ b/src/components/form-designer/widget-panel/widgetsConfig.js @@ -118,6 +118,7 @@ export const basicFields = [ clearable: true, showPassword: false, required: false, + requiredHint: '', validation: '', validationHint: '', //------------------- @@ -163,6 +164,7 @@ export const basicFields = [ disabled: false, hidden: false, required: false, + requiredHint: '', validation: '', validationHint: '', //------------------- @@ -201,6 +203,7 @@ export const basicFields = [ disabled: false, hidden: false, required: false, + requiredHint: '', validation: '', validationHint: '', //------------------- @@ -247,6 +250,7 @@ export const basicFields = [ {label: 'radio 3', value: 3}, ], required: false, + requiredHint: '', validation: '', validationHint: '', //------------------- @@ -286,6 +290,7 @@ export const basicFields = [ {label: 'check 3', value: 3}, ], required: false, + requiredHint: '', validation: '', validationHint: '', //------------------- @@ -330,6 +335,7 @@ export const basicFields = [ {label: 'select 3', value: 3}, ], required: false, + requiredHint: '', validation: '', validationHint: '', //------------------- @@ -370,6 +376,7 @@ export const basicFields = [ editable: false, format: 'HH:mm:ss', //时间格式 required: false, + requiredHint: '', validation: '', validationHint: '', //------------------- @@ -410,6 +417,7 @@ export const basicFields = [ editable: false, format: 'HH:mm:ss', //时间格式 required: false, + requiredHint: '', validation: '', validationHint: '', //------------------- @@ -451,6 +459,7 @@ export const basicFields = [ format: 'YYYY-MM-DD', //日期显示格式 valueFormat: 'YYYY-MM-DD', //日期对象格式 required: false, + requiredHint: '', validation: '', validationHint: '', //------------------- @@ -493,6 +502,7 @@ export const basicFields = [ format: 'YYYY-MM-DD', //日期显示格式 valueFormat: 'YYYY-MM-DD', //日期对象格式 required: false, + requiredHint: '', validation: '', validationHint: '', //------------------- @@ -557,6 +567,7 @@ export const basicFields = [ disabled: false, hidden: false, required: false, + requiredHint: '', validation: '', validationHint: '', //------------------- @@ -594,6 +605,7 @@ export const basicFields = [ disabled: false, hidden: false, required: false, + requiredHint: '', validation: '', validationHint: '', //------------------- @@ -625,6 +637,7 @@ export const basicFields = [ disabled: false, hidden: false, required: false, + requiredHint: '', validation: '', validationHint: '', //------------------- diff --git a/src/components/form-render/container-item/containerItemMixin.js b/src/components/form-render/container-item/containerItemMixin.js index 6b26579..f0163f2 100644 --- a/src/components/form-render/container-item/containerItemMixin.js +++ b/src/components/form-render/container-item/containerItemMixin.js @@ -1,4 +1,4 @@ -import {generateId} from "@/utils/util"; +import { traverseFieldWidgetsOfContainer } from "@/utils/util"; export default { computed: { @@ -14,6 +14,9 @@ export default { }, }, + mounted() { + this.callSetHidden() + }, methods: { unregisterFromRefList() { //销毁容器组件时注销组件ref @@ -23,11 +26,33 @@ export default { } }, + /* 主动触发setHidden()方法,以清空被隐藏容器内字段组件的校验规则!! */ + callSetHidden() { + if (this.widget.options.hidden === true) { + this.setHidden(true) + } + }, + //--------------------- 以下为组件支持外部调用的API方法 begin ------------------// /* 提示:用户可自行扩充这些方法!!! */ setHidden(flag) { this.widget.options.hidden = flag + + /* 容器被隐藏后,需要同步清除容器内部字段组件的校验规则 */ + let clearRulesFn = (fieldWidget) => { + let fwName = fieldWidget.options.name + let fwRef = this.getWidgetRef(fwName) + if (flag && !!fwRef && !!fwRef.clearFieldRules) { + fwRef.clearFieldRules() + } + + if (!flag && !!fwRef && !!fwRef.buildFieldRules) { + fwRef.buildFieldRules() + } + } + + traverseFieldWidgetsOfContainer(this.widget, clearRulesFn) }, activeTab(tabIndex) { //tabIndex从0计数 diff --git a/src/components/form-render/index.vue b/src/components/form-render/index.vue index 7ee9477..e8302e2 100644 --- a/src/components/form-render/index.vue +++ b/src/components/form-render/index.vue @@ -41,7 +41,8 @@ import emitter from '@/utils/emitter' import './container-item/index' import FieldComponents from '@/components/form-designer/form-widget/field-widget/index' - import {deepClone, insertCustomCssToHead, insertGlobalFunctionsToHtml} from "@/utils/util" + import {deepClone, insertCustomCssToHead, insertGlobalFunctionsToHtml, getAllContainerWidgets, + getAllFieldWidgets} from "@/utils/util" import i18n, { changeLocale } from "@/utils/i18n" import eventBus from "@/utils/event-bus" @@ -549,7 +550,23 @@ }) } } - } + }, + + /** + * 获取所有字段组件 + * @returns {*[]} + */ + getFieldWidgets() { + return getAllFieldWidgets(this.formJsonObj.widgetList) + }, + + /** + * 获取所有容器组件 + * @returns {*[]} + */ + getContainerWidgets() { + return getAllContainerWidgets(this.formJsonObj.widgetList) + }, //--------------------- 以上为组件支持外部调用的API方法 end ------------------// diff --git a/src/extension/extension-loader.js b/src/extension/extension-loader.js index 54055ab..f80a47d 100644 --- a/src/extension/extension-loader.js +++ b/src/extension/extension-loader.js @@ -76,7 +76,7 @@ export const loadExtension = function (app) { {label: 'info', value: 'info'}, {label: 'error', value: 'error'}, ] - PERegister.registerCPEditor(app, 'alert-type', 'alert-type-editor', + PERegister.registerCPEditor(app, 'type', 'alert-type-editor', PEFactory.createSelectEditor('type', 'extension.setting.alertType', {optionItems: typeOptions})) diff --git a/src/lang/en-US.js b/src/lang/en-US.js index 71a4c1f..cf3af28 100644 --- a/src/lang/en-US.js +++ b/src/lang/en-US.js @@ -190,6 +190,7 @@ export default { rows: 'Rows', labelHidden: 'Hide Label', required: 'Required', + requiredHint: 'Failure Hint', validation: 'Validation', validationHelp: 'Regular expressions supported', validationHint: 'Validation Hint', diff --git a/src/lang/zh-CN.js b/src/lang/zh-CN.js index 9749426..6a9898e 100644 --- a/src/lang/zh-CN.js +++ b/src/lang/zh-CN.js @@ -190,6 +190,7 @@ export default { rows: '行数', labelHidden: '隐藏字段标签', required: '必填字段', + requiredHint: '必填校验提示', validation: '字段校验', validationHelp: '支持输入正则表达式', validationHint: '校验失败提示', diff --git a/src/utils/config.js b/src/utils/config.js index c414379..9601034 100644 --- a/src/utils/config.js +++ b/src/utils/config.js @@ -8,7 +8,7 @@ export const DESIGNER_OPTIONS = { } -export const VARIANT_FORM_VERSION = '3.0.3' +export const VARIANT_FORM_VERSION = '3.0.4' //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/' diff --git a/src/utils/emitter.js b/src/utils/emitter.js index e705c85..21b1822 100644 --- a/src/utils/emitter.js +++ b/src/utils/emitter.js @@ -2,7 +2,6 @@ function _broadcast(componentName, eventName, params) { this.$children.forEach(function (child) { let name = child.$options.componentName; - if (name === componentName) { //child.$emit.apply(child, [eventName].concat(params)); if (!!child.emit$) { @@ -72,7 +71,28 @@ export default { }, broadcast: function broadcast(componentName, eventName, params) { - _broadcast.call(this, componentName, eventName, params); + /* Vue3移除了$children属性,_broadcast方法已不能使用!! */ + //_broadcast.call(this, componentName, eventName, params); + + if (!!this.widgetRefList) { //FormRender只需遍历自身的widgetRefList属性 + Object.keys(this.widgetRefList).forEach(refName => { + let cmpName = this.widgetRefList[refName].$options.componentName + if (cmpName === componentName) { + let foundRef = this.widgetRefList[refName] + foundRef.emit$.call(foundRef, eventName, params) + } + }) + } + + if (!!this.refList) { //其他组件遍历inject的refList属性 + Object.keys(this.refList).forEach(refName => { + let cmpName = this.refList[refName].$options.componentName + if (cmpName === componentName) { + let foundRef = this.refList[refName] + foundRef.emit$.call(foundRef, eventName, params) + } + }) + } } } }; diff --git a/src/utils/util.js b/src/utils/util.js index 71c3c75..aa04395 100644 --- a/src/utils/util.js +++ b/src/utils/util.js @@ -200,6 +200,89 @@ export function traverseAllWidgets(widgetList, handler) { }) } +function handleWidgetForTraverse(widget, handler) { + if (!!widget.category) { + traverseFieldWidgetsOfContainer(widget, handler) + } else if (widget.formItemFlag) { + handler(widget) + } +} + +/** + * 遍历容器内的字段组件 + * @param con + * @param handler + */ +export function traverseFieldWidgetsOfContainer(con, handler) { + if (con.type === 'grid') { + con.cols.forEach(col => { + col.widgetList.forEach(cw => { + handleWidgetForTraverse(cw, handler) + }) + }) + } else if (con.type === 'table') { + con.rows.forEach(row => { + row.cols.forEach(cell => { + cell.widgetList.forEach(cw => { + handleWidgetForTraverse(cw, handler) + }) + }) + }) + } else if (con.type === 'tab') { + con.tabs.forEach(tab => { + tab.widgetList.forEach(cw => { + handleWidgetForTraverse(cw, handler) + }) + }) + } else if (con.type === 'sub-form') { + con.widgetList.forEach(cw => { + handleWidgetForTraverse(cw, handler) + }) + } else if (con.category === 'container') { //自定义容器 + con.widgetList.forEach(cw => { + handleWidgetForTraverse(cw, handler) + }) + } +} + +/** + * 获取所有字段组件 + * @param widgetList + * @returns {[]} + */ +export function getAllFieldWidgets(widgetList) { + let result = [] + let handlerFn = (w) => { + result.push({ + type: w.type, + name: w.options.name, + field: w + }) + } + traverseFieldWidgets(widgetList, handlerFn) + + return result +} + +/** + * 获取所有容器组件 + * @param widgetList + * @returns {[]} + */ +export function getAllContainerWidgets(widgetList) { + let result = [] + let handlerFn = (w) => { + result.push({ + type: w.type, + name: w.options.name, + container: w + }) + } + traverseContainWidgets(widgetList, handlerFn) + + return result +} + export function copyToClipboard(content, clickEvent, $message, successMsg, errorMsg) { const clipboard = new Clipboard(clickEvent.target, { text: () => content diff --git a/vite.config.js b/vite.config.js index 7ffcf75..076cb03 100644 --- a/vite.config.js +++ b/vite.config.js @@ -52,7 +52,7 @@ export default defineConfig({ }, build: { - minify: false, + //minify: false, commonjsOptions: { exclude: [ 'lib/vuedraggable/dist/vuedraggable.umd.js,', //引号前的逗号不能删,不知何故??