From 9f7d67b17bbe41f32ad96d23f4a605a9cd3c8224 Mon Sep 17 00:00:00 2001 From: roymondchen Date: Thu, 21 Nov 2024 19:11:09 +0800 Subject: [PATCH] =?UTF-8?q?feat(form,editor):=20=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BF=AE=E6=94=B9=E6=95=B0=E6=8D=AE=E8=AE=B0?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../editor/src/components/CodeBlockEditor.vue | 16 ++- packages/editor/src/components/CodeParams.vue | 6 +- packages/editor/src/fields/Code.vue | 3 +- packages/editor/src/fields/CodeSelect.vue | 24 ++-- packages/editor/src/fields/CodeSelectCol.vue | 37 +++++- packages/editor/src/fields/CondOpSelect.vue | 7 +- .../editor/src/fields/DataSourceFields.vue | 45 +++++-- .../editor/src/fields/DataSourceMethods.vue | 86 ++++++++++--- packages/editor/src/fields/DisplayConds.vue | 11 +- packages/editor/src/fields/EventSelect.vue | 33 +++-- packages/editor/src/fields/KeyValue.vue | 4 +- packages/form/src/Form.vue | 23 +++- packages/form/src/FormBox.vue | 14 ++- packages/form/src/FormDialog.vue | 8 +- packages/form/src/FormDrawer.vue | 8 +- packages/form/src/containers/Col.vue | 9 +- packages/form/src/containers/Container.vue | 117 +++++++++++++----- packages/form/src/containers/Fieldset.vue | 19 +-- packages/form/src/containers/GroupList.vue | 36 ++++-- .../form/src/containers/GroupListItem.vue | 6 +- packages/form/src/containers/Panel.vue | 11 +- packages/form/src/containers/Row.vue | 11 +- packages/form/src/containers/Step.vue | 13 +- packages/form/src/containers/Table.vue | 18 ++- packages/form/src/containers/Tabs.vue | 55 +++++--- packages/form/src/fields/DynamicField.vue | 6 +- packages/form/src/schema.ts | 42 ++++--- playground/src/configs/dsl.ts | 12 +- playground/src/configs/formDsl.ts | 19 +++ 29 files changed, 501 insertions(+), 198 deletions(-) diff --git a/packages/editor/src/components/CodeBlockEditor.vue b/packages/editor/src/components/CodeBlockEditor.vue index 5d2c095b..7aee2fb6 100644 --- a/packages/editor/src/components/CodeBlockEditor.vue +++ b/packages/editor/src/components/CodeBlockEditor.vue @@ -63,7 +63,13 @@ import { computed, inject, Ref, ref } from 'vue'; import type { CodeBlockContent } from '@tmagic/core'; import { TMagicButton, TMagicDialog, tMagicMessage, tMagicMessageBox, TMagicTag } from '@tmagic/design'; -import { type FormConfig, type FormState, MFormBox, type TableColumnConfig } from '@tmagic/form'; +import { + type ContainerChangeEventData, + type FormConfig, + type FormState, + MFormBox, + type TableColumnConfig, +} from '@tmagic/form'; import FloatingBox from '@editor/components/FloatingBox.vue'; import { useEditorContentHeight } from '@editor/hooks/use-editor-content-height'; @@ -88,7 +94,7 @@ const props = defineProps<{ }>(); const emit = defineEmits<{ - submit: [values: CodeBlockContent]; + submit: [values: CodeBlockContent, eventData: ContainerChangeEventData]; }>(); const services = inject('services'); @@ -209,9 +215,9 @@ const functionConfig = computed(() => [ }, ]); -const submitForm = (values: CodeBlockContent) => { +const submitForm = (values: CodeBlockContent, data: ContainerChangeEventData) => { changedValue.value = undefined; - emit('submit', values); + emit('submit', values, data); }; const errorHandler = (error: any) => { @@ -238,7 +244,7 @@ const beforeClose = (done: (cancel?: boolean) => void) => { distinguishCancelAndClose: true, }) .then(() => { - changedValue.value && submitForm(changedValue.value); + changedValue.value && submitForm(changedValue.value, { changeRecords: formBox.value?.form?.changeRecords }); done(); }) .catch((action: string) => { diff --git a/packages/editor/src/components/CodeParams.vue b/packages/editor/src/components/CodeParams.vue index c307ea7d..be4778de 100644 --- a/packages/editor/src/components/CodeParams.vue +++ b/packages/editor/src/components/CodeParams.vue @@ -13,7 +13,7 @@ diff --git a/packages/editor/src/fields/CodeSelect.vue b/packages/editor/src/fields/CodeSelect.vue index dc4b78d9..5bfa4988 100644 --- a/packages/editor/src/fields/CodeSelect.vue +++ b/packages/editor/src/fields/CodeSelect.vue @@ -21,8 +21,8 @@ import { isEmpty } from 'lodash-es'; import { HookCodeType, HookType } from '@tmagic/core'; import { TMagicCard } from '@tmagic/design'; -import type { FieldProps, FormItem } from '@tmagic/form'; -import { FormState, MContainer } from '@tmagic/form'; +import type { ContainerChangeEventData, FieldProps, FormItem, GroupListConfig } from '@tmagic/form'; +import { MContainer } from '@tmagic/form'; import type { Services } from '@editor/type'; @@ -30,7 +30,9 @@ defineOptions({ name: 'MFieldsCodeSelect', }); -const emit = defineEmits(['change']); +const emit = defineEmits<{ + change: [v: any, eventData: ContainerChangeEventData]; +}>(); const services = inject('services'); @@ -45,12 +47,12 @@ const props = withDefaults( {}, ); -const codeConfig = computed(() => ({ +const codeConfig = computed(() => ({ type: 'group-list', name: 'hookData', enableToggleMode: false, expandAll: true, - title: (mForm: FormState, { model, index }: any) => { + title: (mForm, { model, index }: any) => { if (model.codeType === HookCodeType.DATA_SOURCE_METHOD) { if (Array.isArray(model.codeId)) { if (model.codeId.length < 2) { @@ -78,11 +80,13 @@ const codeConfig = computed(() => ({ { value: HookCodeType.DATA_SOURCE_METHOD, text: '数据源方法' }, ], defaultValue: 'code', - onChange: (mForm: FormState, v: HookCodeType, { model }: any) => { + onChange: (mForm, v: HookCodeType, { model, prop, changeRecords }) => { if (v === HookCodeType.DATA_SOURCE_METHOD) { model.codeId = []; + changeRecords.push({ propPath: prop.replace('codeType', 'codeId'), value: [] }); } else { model.codeId = ''; + changeRecords.push({ propPath: prop.replace('codeType', 'codeId'), value: '' }); } return v; @@ -93,7 +97,7 @@ const codeConfig = computed(() => ({ name: 'codeId', span: 18, labelWidth: 0, - display: (mForm: FormState, { model }: any) => model.codeType !== HookCodeType.DATA_SOURCE_METHOD, + display: (mForm, { model }) => model.codeType !== HookCodeType.DATA_SOURCE_METHOD, notEditable: () => !services?.codeBlockService.getEditStatus(), }, { @@ -101,7 +105,7 @@ const codeConfig = computed(() => ({ name: 'codeId', span: 18, labelWidth: 0, - display: (mForm: FormState, { model }: any) => model.codeType === HookCodeType.DATA_SOURCE_METHOD, + display: (mForm, { model }) => model.codeType === HookCodeType.DATA_SOURCE_METHOD, notEditable: () => !services?.dataSourceService.get('editable'), }, ], @@ -126,7 +130,5 @@ watch( }, ); -const changeHandler = async () => { - emit('change', props.model[props.name]); -}; +const changeHandler = (v: any, eventData: ContainerChangeEventData) => emit('change', v, eventData); diff --git a/packages/editor/src/fields/CodeSelectCol.vue b/packages/editor/src/fields/CodeSelectCol.vue index b3fbd98c..2987c424 100644 --- a/packages/editor/src/fields/CodeSelectCol.vue +++ b/packages/editor/src/fields/CodeSelectCol.vue @@ -7,7 +7,7 @@ :config="selectConfig" :model="model" :size="size" - @change="onParamsChangeHandler" + @change="onCodeIdChangeHandler" > @@ -41,7 +41,14 @@ import { isEmpty, map } from 'lodash-es'; import type { Id } from '@tmagic/core'; import { TMagicButton } from '@tmagic/design'; -import { createValues, type FieldProps, filterFunction, type FormState, MContainer } from '@tmagic/form'; +import { + type ContainerChangeEventData, + createValues, + type FieldProps, + filterFunction, + type FormState, + MContainer, +} from '@tmagic/form'; import CodeParams from '@editor/components/CodeParams.vue'; import MIcon from '@editor/components/Icon.vue'; @@ -55,7 +62,9 @@ defineOptions({ const mForm = inject('mForm'); const services = inject('services'); const eventBus = inject('eventBus'); -const emit = defineEmits(['change']); +const emit = defineEmits<{ + change: [v: any, eventData: ContainerChangeEventData]; +}>(); const props = withDefaults(defineProps>(), { disabled: false, @@ -125,12 +134,30 @@ const selectConfig = { }, }; +const onCodeIdChangeHandler = (value: any) => { + props.model.params = value.params; + emit('change', props.model, { + changeRecords: [ + { + propPath: props.prop, + value: value[props.name], + }, + ], + }); +}; + /** * 参数值修改更新 */ -const onParamsChangeHandler = (value: any) => { +const onParamsChangeHandler = (value: any, eventData: ContainerChangeEventData) => { props.model.params = value.params; - emit('change', props.model); + emit('change', props.model, { + ...eventData, + changeRecords: (eventData.changeRecords || []).map((item) => ({ + prop: `${props.prop.replace(props.name, '')}${item.propPath}`, + value: item.value, + })), + }); }; const editCode = (id: string) => { diff --git a/packages/editor/src/fields/CondOpSelect.vue b/packages/editor/src/fields/CondOpSelect.vue index 5dc75400..ea33ffcb 100644 --- a/packages/editor/src/fields/CondOpSelect.vue +++ b/packages/editor/src/fields/CondOpSelect.vue @@ -39,7 +39,10 @@ defineOptions({ name: 'MFieldsCondOpSelect', }); -const emit = defineEmits(['change']); +const emit = defineEmits<{ + change: [value: string]; +}>(); + const { dataSourceService } = inject('services') || {}; const props = defineProps>(); @@ -81,7 +84,7 @@ const options = computed(() => { return [...arrayOptions, ...eqOptions, ...numberOptions]; }); -const fieldChangeHandler = (v: string[]) => { +const fieldChangeHandler = (v: string) => { emit('change', v); }; diff --git a/packages/editor/src/fields/DataSourceFields.vue b/packages/editor/src/fields/DataSourceFields.vue index d8c941bc..aa9c3440 100644 --- a/packages/editor/src/fields/DataSourceFields.vue +++ b/packages/editor/src/fields/DataSourceFields.vue @@ -51,7 +51,13 @@ import { inject, Ref, ref } from 'vue'; import type { DataSchema } from '@tmagic/core'; import { TMagicButton, tMagicMessage, tMagicMessageBox } from '@tmagic/design'; -import { type FieldProps, type FormConfig, type FormState, MFormBox } from '@tmagic/form'; +import { + type ContainerChangeEventData, + type FieldProps, + type FormConfig, + type FormState, + MFormBox, +} from '@tmagic/form'; import { type ColumnConfig, MagicTable } from '@tmagic/table'; import { getDefaultValueFromFields } from '@tmagic/utils'; @@ -75,7 +81,9 @@ const props = withDefaults( }, ); -const emit = defineEmits(['change']); +const emit = defineEmits<{ + change: [v: any, eventData?: ContainerChangeEventData]; +}>(); const services = inject('services'); @@ -91,16 +99,29 @@ const newHandler = () => { addDialogVisible.value = true; }; -const fieldChange = ({ index, ...value }: Record) => { - if (index > -1) { - props.model[props.name][index] = value; - } else { - props.model[props.name].push(value); - } - +const fieldChange = ({ index, ...value }: Record, data: ContainerChangeEventData) => { addDialogVisible.value = false; - emit('change', props.model[props.name]); + if (index > -1) { + emit('change', value, { + modifyKey: index, + changeRecords: (data.changeRecords || []).map((item) => ({ + propPath: `${props.prop}.${index}.${item.propPath}`, + value: item.value, + })), + }); + } else { + const modifyKey = props.model[props.name].length; + emit('change', value, { + modifyKey, + changeRecords: [ + { + propPath: `${props.prop}.${modifyKey}`, + value, + }, + ], + }); + } }; const fieldColumns: ColumnConfig[] = [ @@ -310,11 +331,9 @@ const addFromJsonFromChange = ({ data }: { data: string }) => { try { const value = JSON.parse(data); - props.model[props.name] = getFieldsConfig(value, props.model[props.name]); - addFromJsonDialogVisible.value = false; - emit('change', props.model[props.name]); + emit('change', getFieldsConfig(value, props.model[props.name])); } catch (e: any) { tMagicMessage.error(e.message); } diff --git a/packages/editor/src/fields/DataSourceMethods.vue b/packages/editor/src/fields/DataSourceMethods.vue index b01b27b6..b5b564db 100644 --- a/packages/editor/src/fields/DataSourceMethods.vue +++ b/packages/editor/src/fields/DataSourceMethods.vue @@ -21,14 +21,17 @@ diff --git a/packages/editor/src/fields/DisplayConds.vue b/packages/editor/src/fields/DisplayConds.vue index 09f4c032..688ffc1a 100644 --- a/packages/editor/src/fields/DisplayConds.vue +++ b/packages/editor/src/fields/DisplayConds.vue @@ -17,6 +17,7 @@ import { computed, inject } from 'vue'; import type { DisplayCond } from '@tmagic/core'; import { + type ContainerChangeEventData, type FieldProps, type FilterFunction, filterFunction, @@ -33,7 +34,7 @@ defineOptions({ }); const emit = defineEmits<{ - change: [value: DisplayCond[]]; + change: [value: DisplayCond[], eventData?: ContainerChangeEventData]; }>(); const props = withDefaults( @@ -149,7 +150,11 @@ const config = computed(() => ({ ], })); -const changeHandler = (v: DisplayCond[]) => { - emit('change', v); +const changeHandler = (v: DisplayCond[], eventData?: ContainerChangeEventData) => { + if (!Array.isArray(props.model[props.name])) { + props.model[props.name] = []; + } + + emit('change', v, eventData); }; diff --git a/packages/editor/src/fields/EventSelect.vue b/packages/editor/src/fields/EventSelect.vue index 51b4db4a..a60e9bdf 100644 --- a/packages/editor/src/fields/EventSelect.vue +++ b/packages/editor/src/fields/EventSelect.vue @@ -20,6 +20,7 @@ :key="index" :disabled="disabled" :size="size" + :prop="`${prop}.${index}`" :config="actionsConfig" :model="cardItem" :label-width="config.labelWidth || '100px'" @@ -32,7 +33,8 @@ :model="cardItem" :disabled="disabled" :size="size" - @change="onChangeHandler" + :prop="`${prop}.${index}`" + @change="eventNameChangeHandler" > >(); -const emit = defineEmits(['change']); +const emit = defineEmits<{ + change: [v: any, eventData?: ContainerChangeEventData]; +}>(); const services = inject('services'); @@ -355,21 +366,27 @@ const addEvent = () => { name: '', actions: [], }; + if (!props.model[props.name]) { props.model[props.name] = []; } - props.model[props.name].push(defaultEvent); - onChangeHandler(); + + emit('change', defaultEvent, { + modifyKey: props.model[props.name].length, + }); }; // 删除事件 const removeEvent = (index: number) => { if (!props.name) return; props.model[props.name].splice(index, 1); - onChangeHandler(); + emit('change', props.model[props.name]); }; -const onChangeHandler = () => { - emit('change', props.model); +const eventNameChangeHandler = (v: any, eventData: ContainerChangeEventData) => { + emit('change', props.model[props.name], eventData); }; + +const onChangeHandler = (v: any, eventData: ContainerChangeEventData) => + emit('change', props.model[props.name], eventData); diff --git a/packages/editor/src/fields/KeyValue.vue b/packages/editor/src/fields/KeyValue.vue index 48c89e9c..379e7826 100644 --- a/packages/editor/src/fields/KeyValue.vue +++ b/packages/editor/src/fields/KeyValue.vue @@ -86,7 +86,9 @@ const props = withDefaults( }, ); -const emit = defineEmits<(e: 'change', value: Record) => void>(); +const emit = defineEmits<{ + change: [value: Record]; +}>(); const records = ref<[string, string][]>([]); const showCode = ref(false); diff --git a/packages/form/src/Form.vue b/packages/form/src/Form.vue index 84e0b86a..24f1dfd8 100644 --- a/packages/form/src/Form.vue +++ b/packages/form/src/Form.vue @@ -28,7 +28,7 @@ diff --git a/packages/form/src/containers/Container.vue b/packages/form/src/containers/Container.vue index c7a778fa..c000a3b8 100644 --- a/packages/form/src/containers/Container.vue +++ b/packages/form/src/containers/Container.vue @@ -191,12 +191,12 @@