@tmagic/editor 1.8.0-beta.25 → 1.8.0-beta.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/es/Editor.vue_vue_type_script_setup_true_lang.js +10 -16
  2. package/dist/es/components/CodeParams.vue_vue_type_script_setup_true_lang.js +4 -4
  3. package/dist/es/components/CompareForm.vue_vue_type_script_setup_true_lang.js +5 -8
  4. package/dist/es/components/ViewForm.vue_vue_type_script_setup_true_lang.js +3 -5
  5. package/dist/es/fields/Code.vue_vue_type_script_setup_true_lang.js +3 -11
  6. package/dist/es/fields/CodeSelect.vue_vue_type_script_setup_true_lang.js +29 -124
  7. package/dist/es/fields/CodeSelectCol.vue_vue_type_script_setup_true_lang.js +5 -6
  8. package/dist/es/fields/DataSourceFieldSelect/FieldSelect.vue_vue_type_script_setup_true_lang.js +1 -1
  9. package/dist/es/fields/DataSourceFieldSelect/Index.vue_vue_type_script_setup_true_lang.js +4 -5
  10. package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +6 -10
  11. package/dist/es/fields/DataSourceMethodSelect.vue_vue_type_script_setup_true_name_true_lang.js +5 -7
  12. package/dist/es/fields/DataSourceMethods.vue_vue_type_script_setup_true_lang.js +1 -4
  13. package/dist/es/fields/DataSourceMocks.vue_vue_type_script_setup_true_lang.js +4 -6
  14. package/dist/es/fields/DataSourceSelect.vue_vue_type_script_setup_true_lang.js +1 -1
  15. package/dist/es/fields/DisplayConds.vue_vue_type_script_setup_true_lang.js +9 -142
  16. package/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +51 -326
  17. package/dist/es/fields/KeyValue.vue_vue_type_script_setup_true_lang.js +2 -4
  18. package/dist/es/fields/StyleSetter/components/Border.vue_vue_type_script_setup_true_lang.js +3 -34
  19. package/dist/es/fields/StyleSetter/configs.js +663 -0
  20. package/dist/es/fields/StyleSetter/pro/Background.vue_vue_type_script_setup_true_lang.js +5 -108
  21. package/dist/es/fields/StyleSetter/pro/Border.vue_vue_type_script_setup_true_lang.js +3 -9
  22. package/dist/es/fields/StyleSetter/pro/Font.vue_vue_type_script_setup_true_lang.js +5 -102
  23. package/dist/es/fields/StyleSetter/pro/Layout.vue_vue_type_script_setup_true_lang.js +5 -265
  24. package/dist/es/fields/StyleSetter/pro/Position.vue_vue_type_script_setup_true_lang.js +5 -85
  25. package/dist/es/fields/StyleSetter/pro/Transform.vue_vue_type_script_setup_true_lang.js +3 -22
  26. package/dist/es/fields/configs/codeSelect.js +98 -0
  27. package/dist/es/fields/configs/displayConds.js +158 -0
  28. package/dist/es/fields/configs/eventSelect.js +225 -0
  29. package/dist/es/fields/configs/stickyAddButton.js +20 -0
  30. package/dist/es/fields/headless-validation.js +139 -0
  31. package/dist/es/headless.js +2 -0
  32. package/dist/es/hooks/use-compare-form.js +6 -23
  33. package/dist/es/hooks/use-form-context.js +19 -0
  34. package/dist/es/index.js +2 -1
  35. package/dist/es/initService.js +17 -1
  36. package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +1 -7
  37. package/dist/es/layouts/history-list/HistoryListPanel.vue_vue_type_script_setup_true_lang.js +1 -11
  38. package/dist/es/layouts/history-list/useHistoryRevert.js +3 -11
  39. package/dist/es/layouts/props-panel/FormPanel.vue_vue_type_script_setup_true_lang.js +10 -23
  40. package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +3 -13
  41. package/dist/es/layouts/sidebar/code-block/CodeBlockListPanel.vue_vue_type_script_setup_true_lang.js +1 -1
  42. package/dist/es/layouts/sidebar/code-block/useContentMenu.js +1 -1
  43. package/dist/es/layouts/sidebar/data-source/DataSourceListPanel.vue_vue_type_script_setup_true_lang.js +1 -1
  44. package/dist/es/layouts/sidebar/data-source/useContentMenu.js +1 -1
  45. package/dist/es/plugin.js +33 -32
  46. package/dist/es/style.css +116 -60
  47. package/dist/es/utils/data-source/index.js +2 -1
  48. package/dist/es/utils/props.js +1 -4
  49. package/dist/es/utils/type-match-rules.js +2 -2
  50. package/dist/style.css +116 -60
  51. package/dist/themes/magic-admin.css +128 -67
  52. package/dist/tmagic-editor-headless.umd.cjs +10867 -0
  53. package/dist/tmagic-editor.umd.cjs +2123 -2015
  54. package/package.json +12 -7
  55. package/src/Editor.vue +12 -16
  56. package/src/components/CodeParams.vue +10 -4
  57. package/src/components/CompareForm.vue +4 -5
  58. package/src/components/ViewForm.vue +2 -3
  59. package/src/editorProps.ts +1 -2
  60. package/src/fields/Code.vue +2 -10
  61. package/src/fields/CodeSelect.vue +20 -116
  62. package/src/fields/CodeSelectCol.vue +3 -5
  63. package/src/fields/DataSourceFieldSelect/FieldSelect.vue +1 -1
  64. package/src/fields/DataSourceFieldSelect/Index.vue +3 -5
  65. package/src/fields/DataSourceFields.vue +0 -7
  66. package/src/fields/DataSourceMethodSelect.vue +2 -5
  67. package/src/fields/DataSourceMethods.vue +1 -6
  68. package/src/fields/DataSourceMocks.vue +1 -10
  69. package/src/fields/DataSourceSelect.vue +1 -1
  70. package/src/fields/DisplayConds.vue +17 -157
  71. package/src/fields/EventSelect.vue +28 -375
  72. package/src/fields/KeyValue.vue +3 -4
  73. package/src/fields/StyleSetter/components/Border.vue +4 -38
  74. package/src/fields/StyleSetter/configs.ts +690 -0
  75. package/src/fields/StyleSetter/pro/Background.vue +4 -104
  76. package/src/fields/StyleSetter/pro/Border.vue +3 -12
  77. package/src/fields/StyleSetter/pro/Font.vue +4 -123
  78. package/src/fields/StyleSetter/pro/Layout.vue +4 -219
  79. package/src/fields/StyleSetter/pro/Position.vue +6 -110
  80. package/src/fields/StyleSetter/pro/Transform.vue +4 -30
  81. package/src/fields/configs/codeSelect.ts +127 -0
  82. package/src/fields/configs/displayConds.ts +184 -0
  83. package/src/fields/configs/eventSelect.ts +309 -0
  84. package/src/fields/configs/stickyAddButton.ts +31 -0
  85. package/src/fields/headless-validation.ts +177 -0
  86. package/src/headless.ts +33 -0
  87. package/src/hooks/use-compare-form.ts +7 -25
  88. package/src/hooks/use-form-context.ts +40 -0
  89. package/src/index.ts +2 -0
  90. package/src/initService.ts +23 -1
  91. package/src/layouts/history-list/HistoryDiffDialog.vue +0 -10
  92. package/src/layouts/history-list/HistoryListPanel.vue +1 -13
  93. package/src/layouts/history-list/useHistoryRevert.ts +7 -13
  94. package/src/layouts/props-panel/FormPanel.vue +17 -28
  95. package/src/layouts/props-panel/PropsPanel.vue +1 -4
  96. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +1 -1
  97. package/src/layouts/sidebar/code-block/useContentMenu.ts +1 -1
  98. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +1 -1
  99. package/src/layouts/sidebar/data-source/useContentMenu.ts +1 -1
  100. package/src/plugin.ts +32 -33
  101. package/src/theme/code-block.scss +0 -37
  102. package/src/theme/display-conds.scss +4 -0
  103. package/src/theme/event.scss +22 -45
  104. package/src/theme/props-panel.scss +17 -3
  105. package/src/theme/themes/magic-admin/index.scss +12 -1
  106. package/src/type.ts +10 -29
  107. package/src/utils/data-source/index.ts +1 -0
  108. package/src/utils/props.ts +1 -4
  109. package/src/utils/type-match-rules.ts +8 -3
  110. package/types/headless.d.ts +18 -0
  111. package/types/index.d.ts +154 -179
@@ -1,15 +1,17 @@
1
1
  <template>
2
- <MGroupList
3
- style="width: 100%"
4
- :config="config"
5
- :name="name"
6
- :disabled="disabled"
7
- :model="model"
8
- :last-values="lastValues"
9
- :prop="prop"
10
- :size="size"
11
- @change="changeHandler"
12
- ></MGroupList>
2
+ <div class="m-fields-display-conds">
3
+ <MGroupList
4
+ :config="config"
5
+ :name="name"
6
+ :disabled="disabled"
7
+ :model="model"
8
+ :last-values="lastValues"
9
+ :is-compare="isCompareMode"
10
+ :prop="prop"
11
+ :size="size"
12
+ @change="changeHandler"
13
+ ></MGroupList>
14
+ </div>
13
15
  </template>
14
16
 
15
17
  <script lang="ts" setup>
@@ -22,174 +24,32 @@ import {
22
24
  type FieldProps,
23
25
  filterFunction,
24
26
  type FormState,
25
- type GroupListConfig,
26
27
  MGroupList,
27
28
  } from '@tmagic/form';
28
- import { removeDataSourceFieldPrefix } from '@tmagic/utils';
29
29
 
30
- import { useServices } from '@editor/hooks/use-services';
31
- import { getCascaderOptionsFromFields, getFieldType } from '@editor/utils';
30
+ import { createDisplayCondsConfig } from '@editor/fields/configs/displayConds';
32
31
 
33
32
  defineOptions({
34
33
  name: 'm-fields-display-conds',
35
34
  });
36
35
 
37
36
  const emit = defineEmits<{
38
- change: [value: DisplayCond[], eventData?: ContainerChangeEventData];
37
+ change: [value: DisplayCond | DisplayCond[], eventData?: ContainerChangeEventData];
39
38
  }>();
40
39
 
41
40
  const props = withDefaults(defineProps<FieldProps<DisplayCondsConfig>>(), {
42
41
  disabled: false,
43
42
  });
44
43
 
45
- const { dataSourceService } = useServices();
46
44
  const mForm = inject<FormState | undefined>('mForm');
47
45
 
48
46
  const parentFields = computed(() => filterFunction<string[]>(mForm, props.config.parentFields, props) || []);
49
47
 
50
- const resolveFieldPath = (path: string[]) => {
51
- const [id, ...fieldNames] = path;
52
- const ds = id ? dataSourceService.getDataSourceById(removeDataSourceFieldPrefix(`${id}`)) : undefined;
53
- return { ds, fieldNames };
54
- };
55
-
56
- const fieldOnChange = (_formState: FormState | undefined, v: string[], { model }: { model: Record<string, any> }) => {
57
- const { ds, fieldNames } = resolveFieldPath([...parentFields.value, ...v]);
58
- const type = getFieldType(ds, fieldNames);
59
- if (type === 'number') {
60
- model.value = Number(model.value);
61
- } else if (type === 'boolean') {
62
- model.value = Boolean(model.value);
63
- } else if (type === 'null') {
64
- model.value = null;
65
- } else {
66
- model.value = `${model.value}`;
67
- }
68
- return v;
69
- };
70
-
71
- const config = computed<GroupListConfig>(() => ({
72
- type: 'groupList',
73
- name: props.name,
74
- titlePrefix: props.config.titlePrefix,
75
- expandAll: true,
76
- enableToggleMode: false,
77
- flat: props.config.flat,
78
- items: [
79
- {
80
- type: 'table',
81
- name: 'cond',
82
- operateColWidth: props.config.operateColWidth,
83
- enableToggleMode: false,
84
- fixed: props.config.fixed,
85
- flat: props.config.flat,
86
- items: [
87
- parentFields.value.length
88
- ? {
89
- type: 'cascader',
90
- options: () => {
91
- const { ds, fieldNames } = resolveFieldPath(parentFields.value);
92
- if (!ds) {
93
- return [];
94
- }
95
-
96
- let fields = ds.fields || [];
97
- fieldNames.forEach((key) => {
98
- const field = fields.find((f) => f.name === key);
99
- fields = field?.fields || [];
100
- });
48
+ const config = computed(() => createDisplayCondsConfig(props.config, props.name, parentFields.value));
101
49
 
102
- return getCascaderOptionsFromFields(fields, ['string', 'number', 'boolean', 'any']);
103
- },
104
- name: 'field',
105
- value: 'key',
106
- label: '字段',
107
- checkStrictly: false,
108
- onChange: fieldOnChange,
109
- defaultValue: () => [],
110
- rules: [
111
- { required: true, trigger: 'blur', message: '请选择字段' },
112
- { typeMatch: true, trigger: 'change' },
113
- ],
114
- }
115
- : {
116
- type: 'data-source-field-select',
117
- name: 'field',
118
- value: 'key',
119
- label: '字段',
120
- checkStrictly: false,
121
- dataSourceFieldType: ['string', 'number', 'boolean', 'any'],
122
- onChange: fieldOnChange,
123
- defaultValue: () => [],
124
- rules: [
125
- { required: true, trigger: 'blur', message: '请选择字段' },
126
- { typeMatch: true, trigger: 'change' },
127
- ],
128
- },
129
- {
130
- type: 'cond-op-select',
131
- parentFields: parentFields.value,
132
- label: '条件',
133
- width: 140,
134
- name: 'op',
135
- rules: [
136
- { required: true, trigger: 'blur', message: '请选择条件' },
137
- { typeMatch: true, trigger: 'change' },
138
- ],
139
- },
140
- {
141
- label: '值',
142
- width: 160,
143
- items: [
144
- {
145
- name: 'value',
146
- type: (_mForm, { model }) => {
147
- const { ds, fieldNames } = resolveFieldPath([...parentFields.value, ...(model.field || [])]);
148
- const type = getFieldType(ds, fieldNames);
149
-
150
- if (type === 'number') {
151
- return 'number';
152
- }
153
-
154
- if (type === 'boolean') {
155
- return 'select';
156
- }
157
-
158
- if (type === 'null') {
159
- return 'display';
160
- }
161
-
162
- return 'text';
163
- },
164
- options: [
165
- { text: 'true', value: true },
166
- { text: 'false', value: false },
167
- ],
168
- display: (_mForm, { model }) => !['between', 'not_between'].includes(model.op),
169
- displayText: (_mForm: FormState | undefined, { model }: any) => {
170
- if (model.value === null) {
171
- return 'null';
172
- }
173
- return model.value;
174
- },
175
- },
176
- {
177
- name: 'range',
178
- type: 'number-range',
179
- display: (vm, { model }) => ['between', 'not_between'].includes(model.op),
180
- },
181
- ],
182
- },
183
- ],
184
- },
185
- ],
186
- }));
50
+ const isCompareMode = computed(() => Boolean(props.isCompare && props.lastValues));
187
51
 
188
52
  const changeHandler = (v: DisplayCond[], eventData?: ContainerChangeEventData) => {
189
- if (!Array.isArray(props.model[props.name])) {
190
- props.model[props.name] = [];
191
- }
192
-
193
53
  emit('change', v, eventData);
194
54
  };
195
55
  </script>
@@ -15,100 +15,50 @@
15
15
  <div v-else class="fullWidth event-select-container">
16
16
  <div class="event-select-header">
17
17
  <div class="event-select-title">事件配置</div>
18
- <TMagicButton
19
- v-if="!isCompareMode && displayList.length > 0"
20
- class="create-button"
21
- text
22
- type="primary"
23
- :icon="Plus"
24
- :size="size"
25
- :disabled="disabled"
26
- @click="addEvent()"
27
- >添加事件</TMagicButton
28
- >
29
18
  </div>
30
- <MPanel
31
- v-for="entry in displayList"
32
- :key="entry.index"
19
+ <MGroupList
20
+ :config="eventConfig"
21
+ :name="name"
33
22
  :disabled="disabled"
34
- :size="size"
35
- :prop="`${prop}.${entry.index}`"
36
- :config="actionsConfig"
37
- :model="entry.cardItem"
38
- :last-values="entry.lastCardItem"
23
+ :model="model"
24
+ :last-values="lastValues"
39
25
  :is-compare="isCompareMode"
40
- :hide-expand="false"
41
- :label-width="config.labelWidth || '100px'"
26
+ :prop="prop"
27
+ :size="size"
42
28
  @change="onChangeHandler"
43
29
  >
44
- <template #header>
30
+ <template #title="{ model: itemModel, lastValues: itemLastValues, prop: itemProp }">
45
31
  <div class="event-item-header">
46
32
  <MFormContainer
47
33
  class="fullWidth"
48
34
  :config="eventNameConfig"
49
- :model="entry.cardItem"
50
- :last-values="entry.lastCardItem"
35
+ :model="itemModel"
36
+ :last-values="itemLastValues"
51
37
  :is-compare="isCompareMode"
52
38
  :disabled="disabled"
53
39
  :size="size"
54
- :prop="`${prop}.${entry.index}`"
55
- @change="eventNameChangeHandler"
40
+ :prop="itemProp"
41
+ @change="onChangeHandler"
56
42
  ></MFormContainer>
57
- <TMagicButton
58
- class="event-item-delete-button"
59
- v-if="!isCompareMode"
60
- link
61
- :icon="Delete"
62
- :disabled="disabled"
63
- :size="size"
64
- @click="removeEvent(Number(entry.index))"
65
- ></TMagicButton>
66
43
  </div>
67
44
  </template>
68
- </MPanel>
69
-
70
- <TMagicButton
71
- v-if="!isCompareMode"
72
- class="create-button fullWidth"
73
- :icon="Plus"
74
- :disabled="disabled"
75
- @click="addEvent()"
76
- >添加事件</TMagicButton
77
- >
45
+ </MGroupList>
78
46
  </div>
79
47
  </div>
80
48
  </template>
81
49
 
82
50
  <script lang="ts" setup>
83
51
  import { computed } from 'vue';
84
- import { Delete } from '@element-plus/icons-vue';
85
- import { Plus } from '@element-plus/icons-vue';
86
- import { has } from 'lodash-es';
87
52
 
88
- import { ActionType, MNode } from '@tmagic/core';
89
- import { TMagicButton } from '@tmagic/design';
90
- import type {
91
- CodeSelectColConfig,
92
- ContainerChangeEventData,
93
- DataSourceMethodSelectConfig,
94
- DynamicTypeConfig,
95
- EventSelectConfig,
96
- FieldProps,
97
- FormState,
98
- PanelConfig,
99
- TableConfig,
100
- UISelectConfig,
101
- } from '@tmagic/form';
102
- import { defineFormItem, MContainer as MFormContainer, MPanel, MTable } from '@tmagic/form';
53
+ import type { ContainerChangeEventData, EventSelectConfig, FieldProps } from '@tmagic/form';
54
+ import { MContainer as MFormContainer, MGroupList, MTable } from '@tmagic/form';
103
55
 
104
- import { useServices } from '@editor/hooks/use-services';
105
56
  import {
106
- getCompActionAllowedValues,
107
- getCompActionOptions,
108
- getEventNameAllowedValues,
109
- getEventNameOptions,
110
- normalizeCompActionValue,
111
- } from '@editor/utils';
57
+ createEventNameConfig,
58
+ createEventSelectConfig,
59
+ createLegacyTableConfig,
60
+ isLegacyEventValue,
61
+ } from '@editor/fields/configs/eventSelect';
112
62
 
113
63
  defineOptions({
114
64
  name: 'MFieldsEventSelect',
@@ -120,322 +70,25 @@ const emit = defineEmits<{
120
70
  change: [v: any, eventData?: ContainerChangeEventData];
121
71
  }>();
122
72
 
123
- const { editorService, dataSourceService, eventsService, codeBlockService, propsService } = useServices();
124
-
125
- // 事件名称下拉框表单配置
126
- const eventNameConfig = computed(() => {
127
- const defaultEventNameConfig = {
128
- name: 'name',
129
- text: '事件类型',
130
- type: (mForm: FormState | undefined, { formValue }: any) => {
131
- if (
132
- props.config.src !== 'component' ||
133
- (formValue.type === 'page-fragment-container' && formValue.pageFragmentId)
134
- ) {
135
- return 'cascader';
136
- }
137
- return 'select';
138
- },
139
- labelWidth: '70px',
140
- checkStrictly: () => props.config.src !== 'component',
141
- valueSeparator: '.',
142
- options: (_mForm: FormState, { formValue }: any) => getEventNameOptions(props.config.src, formValue),
143
- rules: [
144
- {
145
- validator: ({ value, callback }: any, { formValue }: any) => {
146
- const allowedNames = getEventNameAllowedValues(props.config as any, formValue);
147
- if (allowedNames && allowedNames.size > 0 && value && !allowedNames.has(value)) {
148
- return callback(`事件名(${value})不存在`);
149
- }
150
- callback();
151
- },
152
- trigger: 'blur',
153
- },
154
- ],
155
- };
156
- return { ...defaultEventNameConfig, ...props.config.eventNameConfig };
157
- });
158
-
159
- const actionTypeOptions = computed(() => {
160
- const o: {
161
- text: string;
162
- label: string;
163
- value: string;
164
- disabled?: boolean;
165
- }[] = [
166
- {
167
- text: '组件',
168
- label: '组件',
169
- value: ActionType.COMP,
170
- },
171
- ];
172
-
173
- if (!propsService.getDisabledCodeBlock()) {
174
- o.push({
175
- text: '代码',
176
- label: '代码',
177
- disabled: !Object.keys(codeBlockService.getCodeDsl() || {}).length,
178
- value: ActionType.CODE,
179
- });
180
- }
181
-
182
- if (!propsService.getDisabledDataSource()) {
183
- o.push({
184
- text: '数据源',
185
- label: '数据源',
186
- value: ActionType.DATA_SOURCE,
187
- });
188
- }
189
-
190
- return o;
191
- });
192
-
193
- // 联动类型
194
- const actionTypeConfig = computed(() => {
195
- const defaultActionTypeConfig = {
196
- name: 'actionType',
197
- text: '联动类型',
198
- type: 'select',
199
- labelPosition: 'left',
200
- defaultValue: ActionType.COMP,
201
- options: actionTypeOptions.value,
202
- rules: [
203
- {
204
- required: true,
205
- message: '联动类型不能为空',
206
- },
207
- {
208
- typeMatch: true,
209
- trigger: 'blur',
210
- },
211
- ],
212
- onChange: (_mForm: FormState, _v: string, { setModel }: any) => {
213
- setModel('to', '');
214
- setModel('method', '');
215
- setModel('codeId', '');
216
- setModel('dataSourceMethod', []);
217
- },
218
- };
219
- return { ...defaultActionTypeConfig, ...props.config.actionTypeConfig };
220
- });
221
-
222
- // 联动组件配置
223
- const targetCompConfig = computed(() => {
224
- const defaultTargetCompConfig: UISelectConfig = {
225
- name: 'to',
226
- text: '联动组件',
227
- type: 'ui-select',
228
- labelPosition: 'left',
229
- display: (_mForm, { model }) => model.actionType === ActionType.COMP,
230
- onChange: (_mForm, _v, { setModel }) => {
231
- setModel('method', '');
232
- },
233
- rules: [
234
- {
235
- typeMatch: true,
236
- trigger: 'blur',
237
- },
238
- ],
239
- };
240
- return { ...defaultTargetCompConfig, ...props.config.targetCompConfig };
241
- });
242
-
243
- // 联动组件动作配置
244
- const compActionConfig = computed(() => {
245
- const defaultCompActionConfig: DynamicTypeConfig = {
246
- name: 'method',
247
- text: '动作',
248
- labelPosition: 'left',
249
- type: (mForm: FormState | undefined, { model }: any) => {
250
- const to = editorService.getNodeById(model.to);
251
-
252
- if (to && to.type === 'page-fragment-container' && to.pageFragmentId) {
253
- return 'cascader';
254
- }
255
-
256
- return 'select';
257
- },
258
- checkStrictly: () => props.config.src !== 'component',
259
- display: (mForm: FormState | undefined, { model }: any) => model.actionType === ActionType.COMP,
260
- options: (_mForm: FormState, { model }: any) => getCompActionOptions(model.to),
261
- rules: [
262
- {
263
- trigger: 'blur',
264
- validator: ({ value, callback }: any, { model }: any) => {
265
- const allowedMethods = getCompActionAllowedValues(props.config as any, model);
266
- const normalized = normalizeCompActionValue(value);
267
- if (allowedMethods && allowedMethods.size > 0 && normalized && !allowedMethods.has(normalized)) {
268
- return callback(`动作名(${normalized})不存在`);
269
- }
270
- callback();
271
- },
272
- },
273
- ],
274
- };
275
- return { ...defaultCompActionConfig, ...props.config.compActionConfig };
276
- });
277
-
278
- // 代码联动配置
279
- const codeActionConfig = computed(() => {
280
- const defaultCodeActionConfig: CodeSelectColConfig = {
281
- type: 'code-select-col',
282
- text: '代码块',
283
- name: 'codeId',
284
- notEditable: () => !codeBlockService.getEditStatus(),
285
- display: (mForm, { model }) => model.actionType === ActionType.CODE,
286
- };
287
- return { ...defaultCodeActionConfig, ...props.config.codeActionConfig };
288
- });
73
+ const tableConfig = computed(() => createLegacyTableConfig(props.config));
289
74
 
290
- // 数据源联动配置
291
- const dataSourceActionConfig = computed(() => {
292
- const defaultDataSourceActionConfig: DataSourceMethodSelectConfig = {
293
- type: 'data-source-method-select',
294
- text: '数据源方法',
295
- name: 'dataSourceMethod',
296
- notEditable: () => !dataSourceService.get('editable'),
297
- display: (mForm, { model }) => model.actionType === ActionType.DATA_SOURCE,
298
- };
299
- return { ...defaultDataSourceActionConfig, ...props.config.dataSourceActionConfig };
300
- });
301
-
302
- // 兼容旧的数据格式
303
- const tableConfig = computed(
304
- () =>
305
- defineFormItem({
306
- type: 'table',
307
- name: 'events',
308
- items: [
309
- {
310
- name: 'name',
311
- label: '事件名',
312
- type: eventNameConfig.value.type,
313
- options: (mForm: FormState, { formValue }: any) =>
314
- eventsService
315
- .getEvent(formValue.type, { node: editorService.getNodeById(formValue.id) })
316
- .map((option: any) => ({
317
- text: option.label,
318
- value: option.value,
319
- })),
320
- },
321
- {
322
- name: 'to',
323
- label: '联动组件',
324
- type: 'ui-select',
325
- },
326
- {
327
- name: 'method',
328
- label: '动作',
329
- type: compActionConfig.value.type,
330
- options: (mForm: FormState, { model, formValue }: any) => {
331
- const node = editorService.getNodeById(model.to) || (formValue as MNode);
332
- if (!node?.type) return [];
75
+ const eventNameConfig = computed(() => createEventNameConfig(props.config));
333
76
 
334
- return eventsService.getMethod(node.type, { targetId: model.to, node }).map((option: any) => ({
335
- text: option.label,
336
- value: option.value,
337
- }));
338
- },
339
- },
340
- ],
341
- }) as TableConfig,
342
- );
77
+ const eventConfig = computed(() => createEventSelectConfig(props.config, props.name));
343
78
 
344
- // 组件动作组表单配置
345
- const actionsConfig = computed(
346
- () =>
347
- defineFormItem({
348
- type: 'panel',
349
- labelPosition: 'left',
350
- items: [
351
- {
352
- type: 'group-list',
353
- name: 'actions',
354
- expandAll: true,
355
- enableToggleMode: false,
356
- titlePrefix: '动作',
357
- labelPosition: 'left',
358
- items: [
359
- actionTypeConfig.value,
360
- targetCompConfig.value,
361
- compActionConfig.value,
362
- codeActionConfig.value,
363
- dataSourceActionConfig.value,
364
- ],
365
- },
366
- ],
367
- }) as PanelConfig,
368
- );
369
-
370
- // 是否为旧的数据格式
371
- const isOldVersion = computed(() => {
372
- if (props.model[props.name].length === 0) return false;
373
- return !has(props.model[props.name][0], 'actions');
374
- });
79
+ const isOldVersion = computed(() => isLegacyEventValue(props.model[props.name]));
375
80
 
376
81
  /**
377
82
  * 对比模式判定:
378
83
  *
379
- * event-select 内部由「事件列表 + 嵌套子表单」组成,属于复合字段。父级 `MFormContainer` 已将其
380
- * 归入「自接管对比字段」(见 Container.vue 的 `SELF_DIFF_FIELD_TYPES`),即对比时只渲染一次本组件,
381
- * 并把当前值 `model` 与历史值 `lastValues` 一并传入,由本组件把 `is-compare`/`lastValues` 透传给
382
- * 内部的 MPanel / MFormContainer,逐项(事件名、动作)展示前后差异。
84
+ * event-select 内部是事件列表 group-list。父级 `MFormContainer` 已将其归入「自接管对比字段」
85
+ * (见 Container.vue 的 `SELF_DIFF_FIELD_TYPES`),对比时只渲染一次本组件,并把 `is-compare` /
86
+ * `lastValues` 透传给内部 MGroupList title slot 里的事件名表单。
383
87
  *
384
88
  * 仅当存在历史值时才启用对比,避免 lastValues 缺失时退化为「全部新增」的空对比。
385
89
  */
386
90
  const isCompareMode = computed(() => Boolean(props.isCompare && props.lastValues));
387
91
 
388
- /**
389
- * 待渲染的事件卡片列表。
390
- *
391
- * - 非对比模式:直接映射当前事件列表,`lastCardItem` 为空;
392
- * - 对比模式:按索引对齐当前值与历史值,取两者长度的最大值,使得「新增」(仅当前有)与
393
- * 「删除」(仅历史有)的事件都能被渲染出来;缺失的一侧用空对象兜底,从而让子级正确高亮差异。
394
- */
395
- const displayList = computed<{ cardItem: any; lastCardItem: any; index: number }[]>(() => {
396
- const current = props.model[props.name] || [];
397
-
398
- if (!isCompareMode.value) {
399
- return current.map((cardItem: any, index: number) => ({ cardItem, lastCardItem: undefined, index }));
400
- }
401
-
402
- const last = props.lastValues?.[props.name] || [];
403
- const length = Math.max(current.length, last.length);
404
-
405
- return Array.from({ length }, (_, index) => ({
406
- cardItem: current[index] ?? {},
407
- lastCardItem: last[index] ?? {},
408
- index,
409
- }));
410
- });
411
-
412
- // 添加事件
413
- const addEvent = () => {
414
- const defaultEvent = {
415
- name: '',
416
- actions: [],
417
- };
418
-
419
- if (!props.model[props.name]) {
420
- props.model[props.name] = [];
421
- }
422
-
423
- emit('change', defaultEvent, {
424
- modifyKey: props.model[props.name].length,
425
- });
426
- };
427
-
428
- // 删除事件
429
- const removeEvent = (index: number) => {
430
- if (!props.name) return;
431
- props.model[props.name].splice(index, 1);
432
- emit('change', props.model[props.name]);
433
- };
434
-
435
- const eventNameChangeHandler = (v: any, eventData: ContainerChangeEventData) => {
436
- emit('change', props.model[props.name], eventData);
437
- };
438
-
439
- const onChangeHandler = (v: any, eventData: ContainerChangeEventData) =>
92
+ const onChangeHandler = (_v: any, eventData?: ContainerChangeEventData) =>
440
93
  emit('change', props.model[props.name], eventData);
441
94
  </script>
@@ -44,7 +44,7 @@
44
44
  </div>
45
45
 
46
46
  <MagicCodeEditor
47
- v-if="config.advanced && showCode && !silentMode"
47
+ v-if="config.advanced && showCode"
48
48
  editor-custom-type="m-fields-key-value"
49
49
  language="javascript"
50
50
  :init-values="model[name]"
@@ -60,7 +60,7 @@
60
60
  ></MagicCodeEditor>
61
61
 
62
62
  <TMagicButton
63
- v-if="config.advanced && !isCompare && !silentMode"
63
+ v-if="config.advanced && !isCompare"
64
64
  size="default"
65
65
  :disabled="disabled"
66
66
  link
@@ -75,7 +75,7 @@ import { computed, inject, ref, watchEffect } from 'vue';
75
75
  import { Delete, Plus } from '@element-plus/icons-vue';
76
76
 
77
77
  import { TMagicButton, TMagicInput } from '@tmagic/design';
78
- import { type FieldProps, FORM_SILENT_MODE_KEY, type FormState, type KeyValueConfig } from '@tmagic/form';
78
+ import { type FieldProps, type FormState, type KeyValueConfig } from '@tmagic/form';
79
79
 
80
80
  import CodeIcon from '@editor/icons/CodeIcon.vue';
81
81
  import MagicCodeEditor from '@editor/layouts/CodeEditor.vue';
@@ -93,7 +93,6 @@ const emit = defineEmits<{
93
93
  }>();
94
94
 
95
95
  const mForm = inject<FormState | undefined>('mForm');
96
- const silentMode = inject(FORM_SILENT_MODE_KEY, false);
97
96
 
98
97
  /** 对比模式下隐藏增删/代码切换等操作按钮,仅保留只读展示。 */
99
98
  const isCompare = computed(() => Boolean(mForm?.isCompare));