@tmagic/editor 1.4.8 → 1.4.10

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 (166) hide show
  1. package/dist/style.css +26 -0
  2. package/dist/tmagic-editor.js +3213 -2820
  3. package/dist/tmagic-editor.umd.cjs +3237 -2839
  4. package/package.json +14 -12
  5. package/src/Editor.vue +212 -0
  6. package/src/components/CodeBlockEditor.vue +268 -0
  7. package/src/components/CodeParams.vue +60 -0
  8. package/src/components/ContentMenu.vue +193 -0
  9. package/src/components/FloatingBox.vue +178 -0
  10. package/src/components/Icon.vue +27 -0
  11. package/src/components/Resizer.vue +23 -0
  12. package/src/components/ScrollBar.vue +151 -0
  13. package/src/components/ScrollViewer.vue +128 -0
  14. package/src/components/SearchInput.vue +37 -0
  15. package/src/components/SplitView.vue +186 -0
  16. package/src/components/ToolButton.vue +138 -0
  17. package/src/components/Tree.vue +71 -0
  18. package/src/components/TreeNode.vue +150 -0
  19. package/src/editorProps.ts +120 -0
  20. package/src/fields/Code.vue +50 -0
  21. package/src/fields/CodeLink.vue +80 -0
  22. package/src/fields/CodeSelect.vue +132 -0
  23. package/src/fields/CodeSelectCol.vue +139 -0
  24. package/src/fields/CondOpSelect.vue +87 -0
  25. package/src/fields/DataSourceFieldSelect/FieldSelect.vue +152 -0
  26. package/src/fields/DataSourceFieldSelect/Index.vue +168 -0
  27. package/src/fields/DataSourceFields.vue +329 -0
  28. package/src/fields/DataSourceInput.vue +339 -0
  29. package/src/fields/DataSourceMethodSelect.vue +153 -0
  30. package/src/fields/DataSourceMethods.vue +104 -0
  31. package/src/fields/DataSourceMocks.vue +255 -0
  32. package/src/fields/DataSourceSelect.vue +98 -0
  33. package/src/fields/DisplayConds.vue +145 -0
  34. package/src/fields/EventSelect.vue +375 -0
  35. package/src/fields/KeyValue.vue +137 -0
  36. package/src/fields/PageFragmentSelect.vue +63 -0
  37. package/src/fields/UISelect.vue +135 -0
  38. package/src/hooks/index.ts +24 -0
  39. package/src/hooks/use-code-block-edit.ts +83 -0
  40. package/src/hooks/use-data-source-edit.ts +46 -0
  41. package/src/hooks/use-data-source-method.ts +100 -0
  42. package/src/hooks/use-editor-content-height.ts +26 -0
  43. package/src/hooks/use-filter.ts +55 -0
  44. package/src/hooks/use-float-box.ts +76 -0
  45. package/src/hooks/use-getso.ts +35 -0
  46. package/src/hooks/use-next-float-box-position.ts +29 -0
  47. package/src/hooks/use-node-status.ts +48 -0
  48. package/src/hooks/use-stage.ts +129 -0
  49. package/src/hooks/use-window-rect.ts +20 -0
  50. package/src/icons/AppManageIcon.vue +15 -0
  51. package/src/icons/CenterIcon.vue +13 -0
  52. package/src/icons/CodeIcon.vue +28 -0
  53. package/src/icons/FolderMinusIcon.vue +22 -0
  54. package/src/icons/PinIcon.vue +25 -0
  55. package/src/icons/PinnedIcon.vue +25 -0
  56. package/src/index.ts +124 -0
  57. package/src/initService.ts +448 -0
  58. package/src/layouts/AddPageBox.vue +55 -0
  59. package/src/layouts/CodeEditor.vue +226 -0
  60. package/src/layouts/Framework.vue +165 -0
  61. package/src/layouts/NavMenu.vue +200 -0
  62. package/src/layouts/PropsPanel.vue +131 -0
  63. package/src/layouts/page-bar/AddButton.vue +48 -0
  64. package/src/layouts/page-bar/PageBar.vue +165 -0
  65. package/src/layouts/page-bar/PageBarScrollContainer.vue +192 -0
  66. package/src/layouts/page-bar/PageList.vue +55 -0
  67. package/src/layouts/page-bar/SwitchTypeButton.vue +45 -0
  68. package/src/layouts/sidebar/ComponentListPanel.vue +134 -0
  69. package/src/layouts/sidebar/Sidebar.vue +278 -0
  70. package/src/layouts/sidebar/code-block/CodeBlockList.vue +160 -0
  71. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +70 -0
  72. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +84 -0
  73. package/src/layouts/sidebar/data-source/DataSourceList.vue +172 -0
  74. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +106 -0
  75. package/src/layouts/sidebar/layer/LayerMenu.vue +128 -0
  76. package/src/layouts/sidebar/layer/LayerNodeTool.vue +32 -0
  77. package/src/layouts/sidebar/layer/LayerPanel.vue +119 -0
  78. package/src/layouts/sidebar/layer/use-click.ts +113 -0
  79. package/src/layouts/sidebar/layer/use-drag.ts +167 -0
  80. package/src/layouts/sidebar/layer/use-keybinding.ts +54 -0
  81. package/src/layouts/sidebar/layer/use-node-status.ts +114 -0
  82. package/src/layouts/workspace/Breadcrumb.vue +35 -0
  83. package/src/layouts/workspace/Workspace.vue +46 -0
  84. package/src/layouts/workspace/viewer/NodeListMenu.vue +115 -0
  85. package/src/layouts/workspace/viewer/Stage.vue +246 -0
  86. package/src/layouts/workspace/viewer/StageOverlay.vue +68 -0
  87. package/src/layouts/workspace/viewer/ViewerMenu.vue +145 -0
  88. package/src/services/BaseService.ts +230 -0
  89. package/src/services/codeBlock.ts +327 -0
  90. package/src/services/componentList.ts +58 -0
  91. package/src/services/dataSource.ts +216 -0
  92. package/src/services/dep.ts +152 -0
  93. package/src/services/editor.ts +1135 -0
  94. package/src/services/events.ts +93 -0
  95. package/src/services/history.ts +126 -0
  96. package/src/services/keybinding.ts +220 -0
  97. package/src/services/props.ts +286 -0
  98. package/src/services/stageOverlay.ts +212 -0
  99. package/src/services/storage.ts +155 -0
  100. package/src/services/ui.ts +157 -0
  101. package/src/shims-vue.d.ts +6 -0
  102. package/src/theme/breadcrumb.scss +6 -0
  103. package/src/theme/code-block.scss +6 -0
  104. package/src/theme/code-editor.scss +38 -0
  105. package/src/theme/common/var.scss +14 -0
  106. package/src/theme/component-list-panel.scss +95 -0
  107. package/src/theme/content-menu.scss +76 -0
  108. package/src/theme/data-source-field-select.scss +16 -0
  109. package/src/theme/data-source-field.scss +12 -0
  110. package/src/theme/data-source-fields.scss +13 -0
  111. package/src/theme/data-source-input.scss +18 -0
  112. package/src/theme/data-source-methods.scss +13 -0
  113. package/src/theme/data-source.scss +28 -0
  114. package/src/theme/event.scss +37 -0
  115. package/src/theme/floating-box.scss +32 -0
  116. package/src/theme/framework.scss +69 -0
  117. package/src/theme/icon.scss +12 -0
  118. package/src/theme/index.scss +10 -0
  119. package/src/theme/key-value.scss +20 -0
  120. package/src/theme/layer-panel.scss +26 -0
  121. package/src/theme/layout.scss +9 -0
  122. package/src/theme/nav-menu.scss +78 -0
  123. package/src/theme/page-bar.scss +102 -0
  124. package/src/theme/page-fragment-select.scss +14 -0
  125. package/src/theme/props-panel.scss +55 -0
  126. package/src/theme/resizer.scss +66 -0
  127. package/src/theme/ruler.scss +38 -0
  128. package/src/theme/search-input.scss +14 -0
  129. package/src/theme/sidebar.scss +79 -0
  130. package/src/theme/stage.scss +76 -0
  131. package/src/theme/theme.scss +28 -0
  132. package/src/theme/tree.scss +89 -0
  133. package/src/theme/workspace.scss +9 -0
  134. package/src/type.ts +780 -0
  135. package/src/utils/compose.ts +52 -0
  136. package/src/utils/config.ts +29 -0
  137. package/src/utils/content-menu.ts +95 -0
  138. package/src/utils/data-source/formConfigs/base.ts +30 -0
  139. package/src/utils/data-source/formConfigs/http.ts +60 -0
  140. package/src/utils/data-source/index.ts +249 -0
  141. package/src/utils/editor.ts +313 -0
  142. package/src/utils/idle-task.ts +72 -0
  143. package/src/utils/index.ts +24 -0
  144. package/src/utils/keybinding-config.ts +125 -0
  145. package/src/utils/logger.ts +47 -0
  146. package/src/utils/monaco-editor.ts +8 -0
  147. package/src/utils/operator.ts +106 -0
  148. package/src/utils/props.ts +407 -0
  149. package/src/utils/scroll-viewer.ts +165 -0
  150. package/src/utils/tree.ts +15 -0
  151. package/src/utils/undo-redo.ts +76 -0
  152. package/types/editorProps.d.ts +3 -1
  153. package/types/fields/CondOpSelect.vue.d.ts +17 -0
  154. package/types/fields/DataSourceFieldSelect/FieldSelect.vue.d.ts +36 -0
  155. package/types/fields/{DataSourceFieldSelect.vue.d.ts → DataSourceFieldSelect/Index.vue.d.ts} +1 -1
  156. package/types/fields/DisplayConds.vue.d.ts +32 -0
  157. package/types/index.d.ts +3 -1
  158. package/types/layouts/Framework.vue.d.ts +3 -1
  159. package/types/layouts/PropsPanel.vue.d.ts +21 -21
  160. package/types/layouts/page-bar/PageBar.vue.d.ts +6 -0
  161. package/types/layouts/page-bar/PageBarScrollContainer.vue.d.ts +3 -0
  162. package/types/layouts/page-bar/PageList.vue.d.ts +25 -0
  163. package/types/services/ui.d.ts +1 -0
  164. package/types/type.d.ts +30 -4
  165. package/types/utils/data-source/index.d.ts +1 -0
  166. package/types/utils/props.d.ts +12 -0
@@ -0,0 +1,168 @@
1
+ <template>
2
+ <div class="m-fields-data-source-field-select">
3
+ <FieldSelect
4
+ v-if="showDataSourceFieldSelect || !config.fieldConfig"
5
+ :model-value="model[name]"
6
+ :disabled="disabled"
7
+ :size="size"
8
+ :value="config.value"
9
+ :checkStrictly="checkStrictly"
10
+ :dataSourceFieldType="config.dataSourceFieldType"
11
+ @change="onChangeHandler"
12
+ ></FieldSelect>
13
+
14
+ <component
15
+ v-else
16
+ :is="tagName"
17
+ :config="config.fieldConfig"
18
+ :model="model"
19
+ :name="name"
20
+ :disabled="disabled"
21
+ :size="size"
22
+ :last-values="lastValues"
23
+ :init-values="initValues"
24
+ :values="values"
25
+ :prop="`${prop}${prop ? '.' : ''}${name}`"
26
+ @change="onChangeHandler"
27
+ ></component>
28
+
29
+ <TMagicButton
30
+ v-if="config.fieldConfig"
31
+ style="margin-left: 5px"
32
+ :type="showDataSourceFieldSelect ? 'primary' : 'default'"
33
+ :size="size"
34
+ @click="showDataSourceFieldSelect = !showDataSourceFieldSelect"
35
+ ><MIcon :icon="Coin"></MIcon
36
+ ></TMagicButton>
37
+ </div>
38
+ </template>
39
+
40
+ <script setup lang="ts">
41
+ import { computed, inject, ref, resolveComponent, watch } from 'vue';
42
+ import { Coin } from '@element-plus/icons-vue';
43
+
44
+ import { TMagicButton, tMagicMessage } from '@tmagic/design';
45
+ import type { FieldProps, FormState } from '@tmagic/form';
46
+ import { DataSchema } from '@tmagic/schema';
47
+ import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX } from '@tmagic/utils';
48
+
49
+ import MIcon from '@editor/components/Icon.vue';
50
+ import type { DataSourceFieldSelectConfig, Services } from '@editor/type';
51
+ import { removeDataSourceFieldPrefix } from '@editor/utils';
52
+
53
+ import FieldSelect from './FieldSelect.vue';
54
+
55
+ defineOptions({
56
+ name: 'MFieldsDataSourceFieldSelect',
57
+ });
58
+
59
+ const emit = defineEmits(['change']);
60
+
61
+ const props = withDefaults(defineProps<FieldProps<DataSourceFieldSelectConfig>>(), {
62
+ disabled: false,
63
+ });
64
+
65
+ const showDataSourceFieldSelect = ref(false);
66
+
67
+ watch(
68
+ () => props.model[props.name],
69
+ (value) => {
70
+ if (
71
+ Array.isArray(value) &&
72
+ typeof value[0] === 'string' &&
73
+ value[0].startsWith(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX)
74
+ ) {
75
+ showDataSourceFieldSelect.value = true;
76
+ } else {
77
+ showDataSourceFieldSelect.value = false;
78
+ }
79
+ },
80
+ {
81
+ immediate: true,
82
+ },
83
+ );
84
+
85
+ const services = inject<Services>('services');
86
+ const mForm = inject<FormState | undefined>('mForm');
87
+
88
+ const dataSources = computed(() => services?.dataSourceService.get('dataSources') || []);
89
+
90
+ const type = computed((): string => {
91
+ let type = props.config.fieldConfig?.type;
92
+ if (typeof type === 'function') {
93
+ type = type(mForm, {
94
+ model: props.model,
95
+ });
96
+ }
97
+ if (type === 'form') return '';
98
+ if (type === 'container') return '';
99
+ return type?.replace(/([A-Z])/g, '-$1').toLowerCase() || (props.config.items ? '' : 'text');
100
+ });
101
+
102
+ const tagName = computed(() => {
103
+ const component = resolveComponent(`m-${props.config.items ? 'form' : 'fields'}-${type.value}`);
104
+ if (typeof component !== 'string') return component;
105
+ return 'm-fields-text';
106
+ });
107
+
108
+ const checkStrictly = computed(() => {
109
+ let value: boolean | undefined;
110
+
111
+ if (typeof props.config.checkStrictly !== 'function') {
112
+ value = props.config.checkStrictly;
113
+ } else {
114
+ const dsId = removeDataSourceFieldPrefix(props.model[0]);
115
+ const dataSource = dataSources.value.find((ds) => ds.id === dsId);
116
+
117
+ value = props.config.checkStrictly(mForm, {
118
+ values: mForm?.initValues || {},
119
+ model: props.model,
120
+ parent: mForm?.parentValues || {},
121
+ formValue: mForm?.values || props.model,
122
+ prop: props.prop,
123
+ config: props.config,
124
+ dataSource,
125
+ });
126
+ }
127
+
128
+ return value ?? props.config.value === 'key';
129
+ });
130
+
131
+ const onChangeHandler = (value: string[]) => {
132
+ if (!Array.isArray(value)) {
133
+ emit('change', value);
134
+ return;
135
+ }
136
+
137
+ const [dsId, ...keys] = value;
138
+ const dataSource = dataSources.value.find((ds) => ds.id === removeDataSourceFieldPrefix(dsId));
139
+
140
+ if (!dataSource) {
141
+ emit('change', value);
142
+ return;
143
+ }
144
+
145
+ let fields = dataSource.fields || [];
146
+ let field: DataSchema | undefined;
147
+ (keys || []).forEach((key) => {
148
+ field = fields.find((f) => f.name === key);
149
+ fields = field?.fields || [];
150
+ });
151
+
152
+ const dataSourceFieldType = props.config.dataSourceFieldType || ['any'];
153
+ if (!dataSourceFieldType.length) {
154
+ dataSourceFieldType.push('any');
155
+ }
156
+
157
+ if (
158
+ !keys.length ||
159
+ (field?.type &&
160
+ (field.type === 'any' || dataSourceFieldType.includes('any') || dataSourceFieldType.includes(field.type)))
161
+ ) {
162
+ emit('change', value);
163
+ } else {
164
+ tMagicMessage.error(`请选择类型为${dataSourceFieldType.join('或')}的字段`);
165
+ emit('change', [dsId]);
166
+ }
167
+ };
168
+ </script>
@@ -0,0 +1,329 @@
1
+ <template>
2
+ <div class="m-editor-data-source-fields">
3
+ <MagicTable :data="model[name]" :columns="fieldColumns"></MagicTable>
4
+
5
+ <div class="m-editor-data-source-fields-footer">
6
+ <TMagicButton size="small" :disabled="disabled" plain @click="newFromJsonHandler()">快速添加</TMagicButton>
7
+ <TMagicButton size="small" type="primary" :disabled="disabled" plain @click="newHandler()">添加</TMagicButton>
8
+ </div>
9
+
10
+ <FloatingBox
11
+ v-model:visible="addDialogVisible"
12
+ v-model:width="width"
13
+ v-model:height="editorHeight"
14
+ :title="fieldTitle"
15
+ :position="boxPosition"
16
+ >
17
+ <template #body>
18
+ <MFormBox
19
+ label-width="80px"
20
+ :title="fieldTitle"
21
+ :config="dataSourceFieldsConfig"
22
+ :values="fieldValues"
23
+ :parentValues="model[name]"
24
+ :disabled="disabled"
25
+ @submit="fieldChange"
26
+ ></MFormBox>
27
+ </template>
28
+ </FloatingBox>
29
+
30
+ <FloatingBox
31
+ v-model:visible="addFromJsonDialogVisible"
32
+ v-model:width="width"
33
+ v-model:height="editorHeight"
34
+ title="快速添加数据定义"
35
+ :position="boxPosition"
36
+ >
37
+ <template #body>
38
+ <MFormBox
39
+ :config="jsonFromConfig"
40
+ :values="jsonFromValues"
41
+ :disabled="disabled"
42
+ @submit="addFromJsonFromChange"
43
+ ></MFormBox>
44
+ </template>
45
+ </FloatingBox>
46
+ </div>
47
+ </template>
48
+
49
+ <script setup lang="ts">
50
+ import { inject, Ref, ref } from 'vue';
51
+
52
+ import { TMagicButton, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
53
+ import { type FieldProps, type FormConfig, type FormState, MFormBox } from '@tmagic/form';
54
+ import type { DataSchema } from '@tmagic/schema';
55
+ import { type ColumnConfig, MagicTable } from '@tmagic/table';
56
+ import { getDefaultValueFromFields } from '@tmagic/utils';
57
+
58
+ import FloatingBox from '@editor/components/FloatingBox.vue';
59
+ import { useEditorContentHeight } from '@editor/hooks';
60
+ import { useNextFloatBoxPosition } from '@editor/hooks/use-next-float-box-position';
61
+ import type { Services } from '@editor/type';
62
+
63
+ defineOptions({
64
+ name: 'MFieldsDataSourceFields',
65
+ });
66
+
67
+ const props = withDefaults(
68
+ defineProps<
69
+ FieldProps<{
70
+ type: 'data-source-fields';
71
+ }>
72
+ >(),
73
+ {
74
+ disabled: false,
75
+ },
76
+ );
77
+
78
+ const emit = defineEmits(['change']);
79
+
80
+ const services = inject<Services>('services');
81
+
82
+ const fieldValues = ref<Record<string, any>>({});
83
+ const fieldTitle = ref('');
84
+
85
+ const width = defineModel<number>('width', { default: 670 });
86
+
87
+ const newHandler = () => {
88
+ fieldValues.value = {};
89
+ fieldTitle.value = '新增属性';
90
+ calcBoxPosition();
91
+ addDialogVisible.value = true;
92
+ };
93
+
94
+ const fieldChange = ({ index, ...value }: Record<string, any>) => {
95
+ if (index > -1) {
96
+ props.model[props.name][index] = value;
97
+ } else {
98
+ props.model[props.name].push(value);
99
+ }
100
+
101
+ addDialogVisible.value = false;
102
+
103
+ emit('change', props.model[props.name]);
104
+ };
105
+
106
+ const fieldColumns: ColumnConfig[] = [
107
+ {
108
+ label: '属性名称',
109
+ prop: 'title',
110
+ },
111
+ {
112
+ label: '属性key',
113
+ prop: 'name',
114
+ },
115
+ {
116
+ label: '属性描述',
117
+ prop: 'description',
118
+ },
119
+ {
120
+ label: '默认值',
121
+ prop: 'defaultValue',
122
+ formatter(item, row) {
123
+ try {
124
+ return JSON.stringify(row.defaultValue);
125
+ } catch (e) {
126
+ return row.defaultValue;
127
+ }
128
+ },
129
+ },
130
+ {
131
+ label: '操作',
132
+ fixed: 'right',
133
+ actions: [
134
+ {
135
+ text: '编辑',
136
+ handler: (row: Record<string, any>, index: number) => {
137
+ fieldValues.value = {
138
+ ...row,
139
+ index,
140
+ };
141
+ fieldTitle.value = `编辑${row.title}`;
142
+ calcBoxPosition();
143
+ addDialogVisible.value = true;
144
+ },
145
+ },
146
+ {
147
+ text: '删除',
148
+ buttonType: 'danger',
149
+ handler: async (row: Record<string, any>, index: number) => {
150
+ await tMagicMessageBox.confirm(`确定删除${row.title}(${row.name})?`, '提示');
151
+ props.model[props.name].splice(index, 1);
152
+ emit('change', props.model[props.name]);
153
+ },
154
+ },
155
+ ],
156
+ },
157
+ ];
158
+
159
+ const dataSourceFieldsConfig: FormConfig = [
160
+ { name: 'index', type: 'hidden', filter: 'number', defaultValue: -1 },
161
+ {
162
+ name: 'type',
163
+ text: '数据类型',
164
+ type: 'select',
165
+ defaultValue: 'string',
166
+ options: [
167
+ { text: '字符串', value: 'string' },
168
+ { text: '数字', value: 'number' },
169
+ { text: '布尔值', value: 'boolean' },
170
+ { text: '对象', value: 'object' },
171
+ { text: '数组', value: 'array' },
172
+ { text: 'null', value: 'null' },
173
+ { text: 'any', value: 'any' },
174
+ ],
175
+ onChange: (formState, v: string, { model }) => {
176
+ if (!['any', 'array', 'object'].includes(v)) {
177
+ model.fields = [];
178
+ }
179
+ return v;
180
+ },
181
+ },
182
+ {
183
+ name: 'name',
184
+ text: '字段名称',
185
+ rules: [
186
+ {
187
+ required: true,
188
+ message: '请输入字段名称',
189
+ },
190
+ {
191
+ validator: ({ value, callback }, { model, parent }) => {
192
+ const index = parent.findIndex((item: Record<string, any>) => item.name === value);
193
+ if ((model.index === -1 && index > -1) || (model.index > -1 && index > -1 && index !== model.index)) {
194
+ return callback(`属性key(${value})已存在`);
195
+ }
196
+ callback();
197
+ },
198
+ },
199
+ ],
200
+ },
201
+ {
202
+ name: 'title',
203
+ text: '展示名称',
204
+ rules: [
205
+ {
206
+ required: true,
207
+ message: '请输入展示名称',
208
+ },
209
+ ],
210
+ },
211
+ {
212
+ name: 'description',
213
+ text: '描述',
214
+ type: 'textarea',
215
+ },
216
+ {
217
+ name: 'defaultValue',
218
+ text: '默认值',
219
+ height: '200px',
220
+ parse: true,
221
+ type: (mForm: FormState | undefined, { model }: any) => {
222
+ if (model.type === 'number') return 'number';
223
+ if (model.type === 'boolean') return 'select';
224
+ if (model.type === 'string') return 'text';
225
+
226
+ return 'vs-code';
227
+ },
228
+ options: [
229
+ { text: 'true', value: true },
230
+ { text: 'false', value: false },
231
+ ],
232
+ },
233
+ {
234
+ name: 'enable',
235
+ text: '是否可用',
236
+ type: 'switch',
237
+ defaultValue: true,
238
+ },
239
+ {
240
+ name: 'fields',
241
+ type: 'data-source-fields',
242
+ defaultValue: [],
243
+ display: (formState: FormState | undefined, { model }: any) => model.type === 'object' || model.type === 'array',
244
+ },
245
+ ];
246
+
247
+ const jsonFromConfig: FormConfig = [
248
+ {
249
+ name: 'data',
250
+ type: 'vs-code',
251
+ labelWidth: '0',
252
+ language: 'json',
253
+ height: '600px',
254
+ options: inject('codeOptions', {}),
255
+ },
256
+ ];
257
+
258
+ const jsonFromValues = ref({
259
+ data: {},
260
+ });
261
+
262
+ const newFromJsonHandler = () => {
263
+ jsonFromValues.value.data = getDefaultValueFromFields(props.model[props.name]);
264
+ calcBoxPosition();
265
+ addFromJsonDialogVisible.value = true;
266
+ };
267
+
268
+ const getValueType = (value: any) => {
269
+ if (Array.isArray(value)) return 'array';
270
+ if (value === null) return 'null';
271
+ if (typeof value === 'object') return 'object';
272
+ if (typeof value === 'number') return 'number';
273
+ if (typeof value === 'boolean') return 'boolean';
274
+ if (typeof value === 'string') return 'string';
275
+
276
+ return 'any';
277
+ };
278
+
279
+ const getFieldsConfig = (value: any, fields: DataSchema[] = []) => {
280
+ if (!value || typeof value !== 'object') throw new Error('数据格式错误');
281
+
282
+ const newFields: DataSchema[] = [];
283
+ Object.entries(value).forEach(([key, value]) => {
284
+ const type = getValueType(value);
285
+
286
+ const oldField = fields.find((field) => field.name === key);
287
+
288
+ let childFields: DataSchema[] = [];
289
+ if (Array.isArray(value) && value.length > 0) {
290
+ childFields = getFieldsConfig(value[0], oldField?.fields);
291
+ } else if (type === 'object') {
292
+ childFields = getFieldsConfig(value, oldField?.fields);
293
+ }
294
+
295
+ newFields.push({
296
+ name: key,
297
+ title: oldField?.title || key,
298
+ type,
299
+ description: oldField?.description || '',
300
+ enable: oldField?.enable ?? true,
301
+ defaultValue: value,
302
+ fields: childFields,
303
+ });
304
+ });
305
+
306
+ return newFields;
307
+ };
308
+
309
+ const addFromJsonFromChange = ({ data }: { data: string }) => {
310
+ try {
311
+ const value = JSON.parse(data);
312
+
313
+ props.model[props.name] = getFieldsConfig(value, props.model[props.name]);
314
+
315
+ addFromJsonDialogVisible.value = false;
316
+
317
+ emit('change', props.model[props.name]);
318
+ } catch (e: any) {
319
+ tMagicMessage.error(e.message);
320
+ }
321
+ };
322
+
323
+ const addDialogVisible = defineModel<boolean>('visible', { default: false });
324
+ const addFromJsonDialogVisible = defineModel<boolean>('visible1', { default: false });
325
+ const { height: editorHeight } = useEditorContentHeight();
326
+
327
+ const parentFloating = inject<Ref<HTMLDivElement | null>>('parentFloating', ref(null));
328
+ const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(services?.uiService, parentFloating);
329
+ </script>