@tmagic/editor 1.4.8 → 1.4.9

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 (143) hide show
  1. package/package.json +11 -11
  2. package/src/Editor.vue +211 -0
  3. package/src/components/CodeBlockEditor.vue +268 -0
  4. package/src/components/CodeParams.vue +60 -0
  5. package/src/components/ContentMenu.vue +193 -0
  6. package/src/components/FloatingBox.vue +178 -0
  7. package/src/components/Icon.vue +27 -0
  8. package/src/components/Resizer.vue +23 -0
  9. package/src/components/ScrollBar.vue +151 -0
  10. package/src/components/ScrollViewer.vue +128 -0
  11. package/src/components/SearchInput.vue +37 -0
  12. package/src/components/SplitView.vue +186 -0
  13. package/src/components/ToolButton.vue +138 -0
  14. package/src/components/Tree.vue +71 -0
  15. package/src/components/TreeNode.vue +150 -0
  16. package/src/editorProps.ts +117 -0
  17. package/src/fields/Code.vue +50 -0
  18. package/src/fields/CodeLink.vue +80 -0
  19. package/src/fields/CodeSelect.vue +132 -0
  20. package/src/fields/CodeSelectCol.vue +139 -0
  21. package/src/fields/DataSourceFieldSelect.vue +149 -0
  22. package/src/fields/DataSourceFields.vue +323 -0
  23. package/src/fields/DataSourceInput.vue +339 -0
  24. package/src/fields/DataSourceMethodSelect.vue +153 -0
  25. package/src/fields/DataSourceMethods.vue +104 -0
  26. package/src/fields/DataSourceMocks.vue +255 -0
  27. package/src/fields/DataSourceSelect.vue +98 -0
  28. package/src/fields/EventSelect.vue +375 -0
  29. package/src/fields/KeyValue.vue +137 -0
  30. package/src/fields/PageFragmentSelect.vue +63 -0
  31. package/src/fields/UISelect.vue +135 -0
  32. package/src/hooks/index.ts +24 -0
  33. package/src/hooks/use-code-block-edit.ts +83 -0
  34. package/src/hooks/use-data-source-edit.ts +46 -0
  35. package/src/hooks/use-data-source-method.ts +100 -0
  36. package/src/hooks/use-editor-content-height.ts +26 -0
  37. package/src/hooks/use-filter.ts +55 -0
  38. package/src/hooks/use-float-box.ts +76 -0
  39. package/src/hooks/use-getso.ts +35 -0
  40. package/src/hooks/use-next-float-box-position.ts +29 -0
  41. package/src/hooks/use-node-status.ts +48 -0
  42. package/src/hooks/use-stage.ts +129 -0
  43. package/src/hooks/use-window-rect.ts +20 -0
  44. package/src/icons/AppManageIcon.vue +15 -0
  45. package/src/icons/CenterIcon.vue +13 -0
  46. package/src/icons/CodeIcon.vue +28 -0
  47. package/src/icons/FolderMinusIcon.vue +22 -0
  48. package/src/icons/PinIcon.vue +25 -0
  49. package/src/icons/PinnedIcon.vue +25 -0
  50. package/src/index.ts +118 -0
  51. package/src/initService.ts +448 -0
  52. package/src/layouts/AddPageBox.vue +55 -0
  53. package/src/layouts/CodeEditor.vue +226 -0
  54. package/src/layouts/Framework.vue +163 -0
  55. package/src/layouts/NavMenu.vue +200 -0
  56. package/src/layouts/PropsPanel.vue +131 -0
  57. package/src/layouts/page-bar/AddButton.vue +48 -0
  58. package/src/layouts/page-bar/PageBar.vue +159 -0
  59. package/src/layouts/page-bar/PageBarScrollContainer.vue +156 -0
  60. package/src/layouts/page-bar/SwitchTypeButton.vue +45 -0
  61. package/src/layouts/sidebar/ComponentListPanel.vue +134 -0
  62. package/src/layouts/sidebar/Sidebar.vue +278 -0
  63. package/src/layouts/sidebar/code-block/CodeBlockList.vue +160 -0
  64. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +70 -0
  65. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +84 -0
  66. package/src/layouts/sidebar/data-source/DataSourceList.vue +172 -0
  67. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +106 -0
  68. package/src/layouts/sidebar/layer/LayerMenu.vue +128 -0
  69. package/src/layouts/sidebar/layer/LayerNodeTool.vue +32 -0
  70. package/src/layouts/sidebar/layer/LayerPanel.vue +119 -0
  71. package/src/layouts/sidebar/layer/use-click.ts +113 -0
  72. package/src/layouts/sidebar/layer/use-drag.ts +167 -0
  73. package/src/layouts/sidebar/layer/use-keybinding.ts +54 -0
  74. package/src/layouts/sidebar/layer/use-node-status.ts +114 -0
  75. package/src/layouts/workspace/Breadcrumb.vue +35 -0
  76. package/src/layouts/workspace/Workspace.vue +46 -0
  77. package/src/layouts/workspace/viewer/NodeListMenu.vue +115 -0
  78. package/src/layouts/workspace/viewer/Stage.vue +246 -0
  79. package/src/layouts/workspace/viewer/StageOverlay.vue +68 -0
  80. package/src/layouts/workspace/viewer/ViewerMenu.vue +145 -0
  81. package/src/services/BaseService.ts +230 -0
  82. package/src/services/codeBlock.ts +327 -0
  83. package/src/services/componentList.ts +58 -0
  84. package/src/services/dataSource.ts +216 -0
  85. package/src/services/dep.ts +152 -0
  86. package/src/services/editor.ts +1135 -0
  87. package/src/services/events.ts +93 -0
  88. package/src/services/history.ts +126 -0
  89. package/src/services/keybinding.ts +220 -0
  90. package/src/services/props.ts +286 -0
  91. package/src/services/stageOverlay.ts +212 -0
  92. package/src/services/storage.ts +155 -0
  93. package/src/services/ui.ts +156 -0
  94. package/src/shims-vue.d.ts +6 -0
  95. package/src/theme/breadcrumb.scss +6 -0
  96. package/src/theme/code-block.scss +6 -0
  97. package/src/theme/code-editor.scss +38 -0
  98. package/src/theme/common/var.scss +14 -0
  99. package/src/theme/component-list-panel.scss +95 -0
  100. package/src/theme/content-menu.scss +76 -0
  101. package/src/theme/data-source-field.scss +12 -0
  102. package/src/theme/data-source-fields.scss +13 -0
  103. package/src/theme/data-source-input.scss +18 -0
  104. package/src/theme/data-source-methods.scss +13 -0
  105. package/src/theme/data-source.scss +28 -0
  106. package/src/theme/event.scss +37 -0
  107. package/src/theme/floating-box.scss +32 -0
  108. package/src/theme/framework.scss +69 -0
  109. package/src/theme/icon.scss +12 -0
  110. package/src/theme/index.scss +10 -0
  111. package/src/theme/key-value.scss +20 -0
  112. package/src/theme/layer-panel.scss +26 -0
  113. package/src/theme/layout.scss +9 -0
  114. package/src/theme/nav-menu.scss +78 -0
  115. package/src/theme/page-bar.scss +89 -0
  116. package/src/theme/page-fragment-select.scss +14 -0
  117. package/src/theme/props-panel.scss +55 -0
  118. package/src/theme/resizer.scss +66 -0
  119. package/src/theme/ruler.scss +38 -0
  120. package/src/theme/search-input.scss +14 -0
  121. package/src/theme/sidebar.scss +79 -0
  122. package/src/theme/stage.scss +76 -0
  123. package/src/theme/theme.scss +27 -0
  124. package/src/theme/tree.scss +89 -0
  125. package/src/theme/workspace.scss +9 -0
  126. package/src/type.ts +749 -0
  127. package/src/utils/compose.ts +52 -0
  128. package/src/utils/config.ts +29 -0
  129. package/src/utils/content-menu.ts +95 -0
  130. package/src/utils/data-source/formConfigs/base.ts +30 -0
  131. package/src/utils/data-source/formConfigs/http.ts +60 -0
  132. package/src/utils/data-source/index.ts +243 -0
  133. package/src/utils/editor.ts +313 -0
  134. package/src/utils/idle-task.ts +72 -0
  135. package/src/utils/index.ts +24 -0
  136. package/src/utils/keybinding-config.ts +125 -0
  137. package/src/utils/logger.ts +47 -0
  138. package/src/utils/monaco-editor.ts +8 -0
  139. package/src/utils/operator.ts +106 -0
  140. package/src/utils/props.ts +504 -0
  141. package/src/utils/scroll-viewer.ts +165 -0
  142. package/src/utils/tree.ts +15 -0
  143. package/src/utils/undo-redo.ts +76 -0
@@ -0,0 +1,153 @@
1
+ <template>
2
+ <div class="m-fields-data-source-method-select">
3
+ <div class="data-source-method-select-container">
4
+ <MContainer
5
+ class="select"
6
+ :config="cascaderConfig"
7
+ :model="model"
8
+ :size="size"
9
+ @change="onChangeHandler"
10
+ ></MContainer>
11
+
12
+ <TMagicButton
13
+ v-if="model[name] && isCustomMethod && hasDataSourceSidePanel"
14
+ class="m-fields-select-action-button"
15
+ :size="size"
16
+ @click="editCodeHandler"
17
+ >
18
+ <MIcon :icon="!notEditable ? Edit : View"></MIcon>
19
+ </TMagicButton>
20
+ </div>
21
+
22
+ <CodeParams
23
+ v-if="paramsConfig.length"
24
+ name="params"
25
+ :model="model"
26
+ :size="size"
27
+ :disabled="disabled"
28
+ :params-config="paramsConfig"
29
+ @change="onChangeHandler"
30
+ ></CodeParams>
31
+ </div>
32
+ </template>
33
+
34
+ <script lang="ts" setup name="">
35
+ import { computed, inject, ref } from 'vue';
36
+ import { Edit, View } from '@element-plus/icons-vue';
37
+
38
+ import { TMagicButton } from '@tmagic/design';
39
+ import { createValues, type FieldProps, filterFunction, type FormState, MContainer } from '@tmagic/form';
40
+ import type { Id } from '@tmagic/schema';
41
+
42
+ import CodeParams from '@editor/components/CodeParams.vue';
43
+ import MIcon from '@editor/components/Icon.vue';
44
+ import type { CodeParamStatement, DataSourceMethodSelectConfig, EventBus, Services } from '@editor/type';
45
+ import { SideItemKey } from '@editor/type';
46
+
47
+ defineOptions({
48
+ name: 'MFieldsDataSourceMethodSelect',
49
+ });
50
+
51
+ const mForm = inject<FormState | undefined>('mForm');
52
+ const services = inject<Services>('services');
53
+ const eventBus = inject<EventBus>('eventBus');
54
+
55
+ const emit = defineEmits(['change']);
56
+
57
+ const dataSourceService = services?.dataSourceService;
58
+
59
+ const props = withDefaults(defineProps<FieldProps<DataSourceMethodSelectConfig>>(), {
60
+ disabled: false,
61
+ });
62
+
63
+ const hasDataSourceSidePanel = computed(() =>
64
+ (services?.uiService.get('sideBarItems') || []).find((item) => item.$key === SideItemKey.DATA_SOURCE),
65
+ );
66
+
67
+ const notEditable = computed(() => filterFunction(mForm, props.config.notEditable, props));
68
+
69
+ const dataSources = computed(() => dataSourceService?.get('dataSources'));
70
+
71
+ const isCustomMethod = computed(() => {
72
+ const [id, name] = props.model[props.name];
73
+
74
+ const dataSource = dataSourceService?.getDataSourceById(id);
75
+
76
+ return Boolean(dataSource?.methods.find((method) => method.name === name));
77
+ });
78
+
79
+ const getParamItemsConfig = ([dataSourceId, methodName]: [Id, string] = ['', '']): CodeParamStatement[] => {
80
+ if (!dataSourceId) return [];
81
+
82
+ const paramStatements = dataSources.value
83
+ ?.find((item) => item.id === dataSourceId)
84
+ ?.methods?.find((item) => item.name === methodName)?.params;
85
+
86
+ if (!paramStatements) return [];
87
+
88
+ return paramStatements.map((paramState: CodeParamStatement) => ({
89
+ text: paramState.name,
90
+ ...paramState,
91
+ }));
92
+ };
93
+
94
+ const paramsConfig = ref<CodeParamStatement[]>(getParamItemsConfig(props.model.dataSourceMethod));
95
+
96
+ const setParamsConfig = (dataSourceMethod: [Id, string], formState: any = {}) => {
97
+ // 通过下拉框选择的codeId变化后修正model的值,避免写入其他codeId的params
98
+ paramsConfig.value = dataSourceMethod ? getParamItemsConfig(dataSourceMethod) : [];
99
+
100
+ if (paramsConfig.value.length) {
101
+ props.model.params = createValues(formState, paramsConfig.value, {}, props.model.params);
102
+ } else {
103
+ props.model.params = {};
104
+ }
105
+ };
106
+
107
+ const methodsOptions = computed(
108
+ () =>
109
+ dataSources.value
110
+ ?.filter((ds) => ds.methods?.length || dataSourceService?.getFormMethod(ds.type).length)
111
+ ?.map((ds) => ({
112
+ label: ds.title || ds.id,
113
+ value: ds.id,
114
+ children: [
115
+ ...(dataSourceService?.getFormMethod(ds.type) || []),
116
+ ...(ds.methods || []).map((method) => ({
117
+ label: method.name,
118
+ value: method.name,
119
+ })),
120
+ ],
121
+ })) || [],
122
+ );
123
+
124
+ const cascaderConfig = computed(() => ({
125
+ type: 'cascader',
126
+ name: props.name,
127
+ options: methodsOptions.value,
128
+ disable: props.disabled,
129
+ onChange: (formState: any, dataSourceMethod: [Id, string]) => {
130
+ setParamsConfig(dataSourceMethod, formState);
131
+
132
+ return dataSourceMethod;
133
+ },
134
+ }));
135
+
136
+ /**
137
+ * 参数值修改更新
138
+ */
139
+ const onChangeHandler = (value: any) => {
140
+ props.model.params = value.params;
141
+ emit('change', props.model);
142
+ };
143
+
144
+ const editCodeHandler = () => {
145
+ const [id] = props.model[props.name];
146
+
147
+ const dataSource = dataSourceService?.getDataSourceById(id);
148
+
149
+ if (!dataSource) return;
150
+
151
+ eventBus?.emit('edit-data-source', id);
152
+ };
153
+ </script>
@@ -0,0 +1,104 @@
1
+ <template>
2
+ <div class="m-editor-data-source-methods">
3
+ <MagicTable :data="model[name]" :columns="methodColumns"></MagicTable>
4
+
5
+ <div class="m-editor-data-source-methods-footer">
6
+ <TMagicButton size="small" type="primary" :disabled="disabled" plain @click="createCodeHandler"
7
+ >添加</TMagicButton
8
+ >
9
+ </div>
10
+
11
+ <CodeBlockEditor
12
+ v-if="codeConfig"
13
+ ref="codeBlockEditor"
14
+ :disabled="disabled"
15
+ :content="codeConfig"
16
+ :is-data-source="true"
17
+ :data-source-type="model.type"
18
+ @submit="submitCodeHandler"
19
+ ></CodeBlockEditor>
20
+ </div>
21
+ </template>
22
+
23
+ <script setup lang="ts">
24
+ import { TMagicButton } from '@tmagic/design';
25
+ import type { FieldProps } from '@tmagic/form';
26
+ import type { CodeBlockContent } from '@tmagic/schema';
27
+ import { type ColumnConfig, MagicTable } from '@tmagic/table';
28
+
29
+ import CodeBlockEditor from '@editor/components/CodeBlockEditor.vue';
30
+ import { useDataSourceMethod } from '@editor/hooks/use-data-source-method';
31
+ import type { CodeParamStatement } from '@editor/type';
32
+
33
+ defineOptions({
34
+ name: 'MFieldsDataSourceMethods',
35
+ });
36
+
37
+ const props = withDefaults(
38
+ defineProps<
39
+ FieldProps<{
40
+ type: 'data-source-methods';
41
+ }>
42
+ >(),
43
+ {
44
+ disabled: false,
45
+ },
46
+ );
47
+
48
+ const emit = defineEmits(['change']);
49
+
50
+ const { codeConfig, codeBlockEditor, createCode, editCode, deleteCode, submitCode } = useDataSourceMethod();
51
+
52
+ const methodColumns: ColumnConfig[] = [
53
+ {
54
+ label: '名称',
55
+ prop: 'name',
56
+ },
57
+ {
58
+ label: '描述',
59
+ prop: 'desc',
60
+ },
61
+ {
62
+ label: '执行时机',
63
+ prop: 'timing',
64
+ },
65
+ {
66
+ label: '参数',
67
+ prop: 'params',
68
+ formatter: (params: CodeParamStatement[]) => params.map((item) => item.name).join(', '),
69
+ },
70
+ {
71
+ label: '操作',
72
+ fixed: 'right',
73
+ actions: [
74
+ {
75
+ text: '编辑',
76
+ handler: (row: CodeBlockContent) => {
77
+ editCode(props.model, row.name);
78
+ emit('change', props.model[props.name]);
79
+ },
80
+ },
81
+ {
82
+ text: '删除',
83
+ buttonType: 'danger',
84
+ handler: (row: CodeBlockContent) => {
85
+ deleteCode(props.model, row.name);
86
+ emit('change', props.model[props.name]);
87
+ },
88
+ },
89
+ ],
90
+ },
91
+ ];
92
+
93
+ const createCodeHandler = () => {
94
+ createCode(props.model);
95
+
96
+ emit('change', props.model[props.name]);
97
+ };
98
+
99
+ const submitCodeHandler = (values: CodeBlockContent) => {
100
+ submitCode(values);
101
+
102
+ emit('change', props.model[props.name]);
103
+ };
104
+ </script>
@@ -0,0 +1,255 @@
1
+ <template>
2
+ <div class="m-editor-data-source-fields">
3
+ <MagicTable :data="model[name]" :columns="columns"></MagicTable>
4
+
5
+ <div class="m-editor-data-source-fields-footer">
6
+ <TMagicButton size="small" type="primary" :disabled="disabled" plain @click="newHandler()">添加</TMagicButton>
7
+ </div>
8
+
9
+ <FloatingBox
10
+ v-model:visible="addDialogVisible"
11
+ v-model:width="width"
12
+ v-model:height="editorHeight"
13
+ :title="drawerTitle"
14
+ :position="boxPosition"
15
+ >
16
+ <template #body>
17
+ <MFormBox
18
+ ref="addDialog"
19
+ label-width="120px"
20
+ :config="formConfig"
21
+ :values="formValues"
22
+ :parentValues="model[name]"
23
+ :disabled="disabled"
24
+ @submit="formChangeHandler"
25
+ ></MFormBox>
26
+ </template>
27
+ </FloatingBox>
28
+ </div>
29
+ </template>
30
+
31
+ <script setup lang="ts">
32
+ import { inject, Ref, ref } from 'vue';
33
+
34
+ import { TMagicButton, tMagicMessageBox, TMagicSwitch } from '@tmagic/design';
35
+ import { type FieldProps, type FormConfig, type FormState, MFormBox } from '@tmagic/form';
36
+ import type { MockSchema } from '@tmagic/schema';
37
+ import { type ColumnConfig, MagicTable } from '@tmagic/table';
38
+ import { getDefaultValueFromFields } from '@tmagic/utils';
39
+
40
+ import FloatingBox from '@editor/components/FloatingBox.vue';
41
+ import { useNextFloatBoxPosition } from '@editor/hooks/use-next-float-box-position';
42
+ import CodeEditor from '@editor/layouts/CodeEditor.vue';
43
+ import { Services } from '@editor/type';
44
+
45
+ import { useEditorContentHeight } from '..';
46
+
47
+ defineOptions({
48
+ name: 'MFieldsDataSourceMocks',
49
+ });
50
+
51
+ const props = withDefaults(
52
+ defineProps<
53
+ FieldProps<{
54
+ type: 'data-source-mocks';
55
+ }>
56
+ >(),
57
+ {
58
+ disabled: false,
59
+ },
60
+ );
61
+
62
+ const emit = defineEmits(['change']);
63
+
64
+ const services = inject<Services>('services');
65
+ const width = defineModel<number>('width', { default: 670 });
66
+
67
+ const drawerTitle = ref('');
68
+ const formValues = ref<Record<string, any>>({});
69
+
70
+ const formConfig: FormConfig = [
71
+ { name: 'index', type: 'hidden', filter: 'number', defaultValue: -1 },
72
+ {
73
+ name: 'title',
74
+ text: '名称',
75
+ rules: [
76
+ {
77
+ required: true,
78
+ message: '请输入字段名称',
79
+ },
80
+ {
81
+ required: true,
82
+ message: '请输入名称',
83
+ },
84
+ ],
85
+ },
86
+ {
87
+ name: 'description',
88
+ text: '描述',
89
+ },
90
+ {
91
+ name: 'enable',
92
+ text: '启用',
93
+ type: 'switch',
94
+ },
95
+ {
96
+ name: 'useInEditor',
97
+ text: '编辑器中使用',
98
+ type: 'switch',
99
+ },
100
+ {
101
+ name: 'data',
102
+ text: 'mock数据',
103
+ type: 'vs-code',
104
+ language: 'json',
105
+ options: inject('codeOptions', {}),
106
+ defaultValue: '{}',
107
+ height: '400px',
108
+ onChange: (formState: FormState | undefined, v: string | any) => {
109
+ if (typeof v !== 'string') return v;
110
+ return JSON.parse(v);
111
+ },
112
+ rules: [
113
+ {
114
+ validator: ({ value, callback }) => {
115
+ if (typeof value !== 'string') return callback();
116
+
117
+ try {
118
+ // 检测json是否存在语法错误
119
+ JSON.parse(value);
120
+
121
+ callback();
122
+ } catch (error: any) {
123
+ callback(error);
124
+ }
125
+ },
126
+ },
127
+ ],
128
+ },
129
+ ];
130
+
131
+ const columns: ColumnConfig[] = [
132
+ {
133
+ type: 'expand',
134
+ component: CodeEditor,
135
+ props: (row: MockSchema) => ({
136
+ initValues: row.data,
137
+ language: 'json',
138
+ height: '150px',
139
+ options: {
140
+ readOnly: true,
141
+ },
142
+ }),
143
+ },
144
+ {
145
+ label: '名称',
146
+ prop: 'title',
147
+ },
148
+ {
149
+ label: '描述',
150
+ prop: 'description',
151
+ },
152
+ {
153
+ label: '是否启用',
154
+ prop: 'enable',
155
+ type: 'component',
156
+ component: TMagicSwitch,
157
+ props: (row: MockSchema) => ({
158
+ modelValue: row.enable,
159
+ activeValue: true,
160
+ inactiveValue: false,
161
+ }),
162
+ listeners: (row: MockSchema, index: number) => ({
163
+ 'update:modelValue': (v: boolean) => {
164
+ toggleValue(row, 'enable', v, index);
165
+ },
166
+ }),
167
+ },
168
+ {
169
+ label: '编辑器中使用',
170
+ prop: 'useInEditor',
171
+ type: 'component',
172
+ component: TMagicSwitch,
173
+ props: (row: MockSchema) => ({
174
+ modelValue: row.useInEditor,
175
+ activeValue: true,
176
+ inactiveValue: false,
177
+ }),
178
+ listeners: (row: MockSchema, index: number) => ({
179
+ 'update:modelValue': (v: boolean) => {
180
+ toggleValue(row, 'useInEditor', v, index);
181
+ },
182
+ }),
183
+ },
184
+ {
185
+ label: '操作',
186
+ fixed: 'right',
187
+ actions: [
188
+ {
189
+ text: '编辑',
190
+ handler: (row: MockSchema, index: number) => {
191
+ formValues.value = {
192
+ ...row,
193
+ index,
194
+ };
195
+ drawerTitle.value = `编辑${row.title}`;
196
+ calcBoxPosition();
197
+ addDialogVisible.value = true;
198
+ },
199
+ },
200
+ {
201
+ text: '删除',
202
+ buttonType: 'danger',
203
+ handler: async (row: MockSchema, index: number) => {
204
+ await tMagicMessageBox.confirm(`确定删除${row.title}?`, '提示');
205
+ props.model[props.name].splice(index, 1);
206
+ emit('change', props.model[props.name]);
207
+ },
208
+ },
209
+ ],
210
+ },
211
+ ];
212
+
213
+ const newHandler = () => {
214
+ const isFirstRow = props.model[props.name].length === 0;
215
+ formValues.value = {
216
+ data: getDefaultValueFromFields(props.model.fields || []),
217
+ useInEditor: isFirstRow,
218
+ enable: isFirstRow,
219
+ };
220
+ drawerTitle.value = '新增Mock';
221
+ calcBoxPosition();
222
+ addDialogVisible.value = true;
223
+ };
224
+
225
+ const formChangeHandler = ({ index, ...value }: Record<string, any>) => {
226
+ if (index > -1) {
227
+ props.model[props.name][index] = value;
228
+ } else {
229
+ props.model[props.name].push(value);
230
+ }
231
+
232
+ addDialogVisible.value = false;
233
+
234
+ emit('change', props.model[props.name]);
235
+ };
236
+
237
+ const toggleValue = (row: MockSchema, key: 'enable' | 'useInEditor', value: boolean, index: number) => {
238
+ if (value) {
239
+ props.model[props.name].forEach((item: MockSchema) => {
240
+ item[key] = false;
241
+ });
242
+ }
243
+
244
+ formChangeHandler({
245
+ ...row,
246
+ [key]: value,
247
+ index,
248
+ });
249
+ };
250
+
251
+ const addDialogVisible = defineModel<boolean>('visible', { default: false });
252
+ const { height: editorHeight } = useEditorContentHeight();
253
+ const parentFloating = inject<Ref<HTMLDivElement | null>>('parentFloating', ref(null));
254
+ const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(services?.uiService, parentFloating);
255
+ </script>
@@ -0,0 +1,98 @@
1
+ <template>
2
+ <div class="m-fields-data-source-select">
3
+ <MSelect
4
+ :model="model"
5
+ :name="name"
6
+ :size="size"
7
+ :prop="prop"
8
+ :disabled="disabled"
9
+ :config="selectConfig"
10
+ :last-values="lastValues"
11
+ @change="changeHandler"
12
+ ></MSelect>
13
+
14
+ <TMagicButton
15
+ v-if="model[name] && hasDataSourceSidePanel"
16
+ class="m-fields-select-action-button"
17
+ :size="size"
18
+ @click="editHandler"
19
+ ><MIcon :icon="!notEditable ? Edit : View"></MIcon
20
+ ></TMagicButton>
21
+ </div>
22
+ </template>
23
+
24
+ <script setup lang="ts">
25
+ import { computed, inject } from 'vue';
26
+ import { Edit, View } from '@element-plus/icons-vue';
27
+
28
+ import { TMagicButton } from '@tmagic/design';
29
+ import { type FieldProps, filterFunction, type FormState, MSelect, type SelectConfig } from '@tmagic/form';
30
+
31
+ import MIcon from '@editor/components/Icon.vue';
32
+ import type { DataSourceSelect, EventBus, Services } from '@editor/type';
33
+ import { SideItemKey } from '@editor/type';
34
+
35
+ defineOptions({
36
+ name: 'MFieldsDataSourceSelect',
37
+ });
38
+
39
+ const emit = defineEmits(['change']);
40
+
41
+ const props = withDefaults(defineProps<FieldProps<DataSourceSelect>>(), {
42
+ disabled: false,
43
+ });
44
+
45
+ const mForm = inject<FormState | undefined>('mForm');
46
+ const { dataSourceService, uiService } = inject<Services>('services') || {};
47
+ const eventBus = inject<EventBus>('eventBus');
48
+
49
+ const dataSources = computed(() => dataSourceService?.get('dataSources') || []);
50
+
51
+ const notEditable = computed(() => filterFunction(mForm, props.config.notEditable, props));
52
+
53
+ const hasDataSourceSidePanel = computed(() =>
54
+ (uiService?.get('sideBarItems') || []).find((item) => item.$key === SideItemKey.DATA_SOURCE),
55
+ );
56
+
57
+ const selectConfig = computed<SelectConfig>(() => {
58
+ const { type, dataSourceType, value, ...config } = props.config;
59
+
60
+ const valueIsId = props.config.value === 'id';
61
+
62
+ return {
63
+ ...config,
64
+ type: 'select',
65
+ valueKey: 'dataSourceId',
66
+ options: dataSources.value
67
+ .filter((ds) => !props.config.dataSourceType || ds.type === props.config.dataSourceType)
68
+ .map((ds) => ({
69
+ value: valueIsId
70
+ ? ds.id
71
+ : {
72
+ isBindDataSource: true,
73
+ dataSourceType: ds.type,
74
+ dataSourceId: ds.id,
75
+ },
76
+ text: ds.title || ds.id,
77
+ })),
78
+ };
79
+ });
80
+
81
+ const changeHandler = (value: any) => {
82
+ emit('change', value);
83
+ };
84
+
85
+ const editHandler = () => {
86
+ const value = props.model[props.name];
87
+
88
+ if (!value) return;
89
+
90
+ const id = typeof value === 'string' ? value : value.dataSourceId;
91
+
92
+ const dataSource = dataSourceService?.getDataSourceById(id);
93
+
94
+ if (!dataSource) return;
95
+
96
+ eventBus?.emit('edit-data-source', id);
97
+ };
98
+ </script>