@tmagic/editor 1.2.0-beta.9 → 1.2.0

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 (98) hide show
  1. package/dist/style.css +59 -35
  2. package/dist/{tmagic-editor.mjs → tmagic-editor.js} +1473 -1154
  3. package/dist/tmagic-editor.js.map +1 -0
  4. package/dist/{tmagic-editor.umd.js → tmagic-editor.umd.cjs} +1483 -1159
  5. package/dist/tmagic-editor.umd.cjs.map +1 -0
  6. package/package.json +16 -14
  7. package/src/Editor.vue +66 -40
  8. package/src/components/CodeDraftEditor.vue +145 -0
  9. package/src/components/ContentMenu.vue +1 -1
  10. package/src/components/FunctionEditor.vue +145 -0
  11. package/src/components/Icon.vue +1 -1
  12. package/src/{layouts → components}/Layout.vue +54 -15
  13. package/src/components/ScrollBar.vue +1 -1
  14. package/src/components/ScrollViewer.vue +10 -1
  15. package/src/components/ToolButton.vue +1 -1
  16. package/src/fields/Code.vue +1 -1
  17. package/src/fields/CodeLink.vue +1 -1
  18. package/src/fields/CodeSelect.vue +89 -102
  19. package/src/fields/UISelect.vue +1 -1
  20. package/src/index.ts +1 -0
  21. package/src/layouts/AddPageBox.vue +1 -1
  22. package/src/layouts/CodeEditor.vue +2 -3
  23. package/src/layouts/Framework.vue +2 -2
  24. package/src/layouts/NavMenu.vue +2 -2
  25. package/src/layouts/PropsPanel.vue +13 -6
  26. package/src/layouts/Resizer.vue +1 -1
  27. package/src/layouts/sidebar/ComponentListPanel.vue +1 -1
  28. package/src/layouts/sidebar/LayerMenu.vue +9 -7
  29. package/src/layouts/sidebar/LayerPanel.vue +127 -174
  30. package/src/layouts/sidebar/Sidebar.vue +110 -26
  31. package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +27 -83
  32. package/src/layouts/sidebar/code-block/CodeBlockList.vue +90 -122
  33. package/src/layouts/workspace/Breadcrumb.vue +1 -1
  34. package/src/layouts/workspace/PageBar.vue +1 -1
  35. package/src/layouts/workspace/PageBarScrollContainer.vue +1 -1
  36. package/src/layouts/workspace/Stage.vue +26 -9
  37. package/src/layouts/workspace/ViewerMenu.vue +11 -9
  38. package/src/layouts/workspace/Workspace.vue +7 -3
  39. package/src/services/BaseService.ts +10 -1
  40. package/src/services/codeBlock.ts +124 -125
  41. package/src/services/componentList.ts +6 -1
  42. package/src/services/editor.ts +54 -18
  43. package/src/services/events.ts +6 -1
  44. package/src/services/history.ts +7 -16
  45. package/src/services/props.ts +7 -2
  46. package/src/services/storage.ts +1 -0
  47. package/src/services/ui.ts +12 -0
  48. package/src/theme/code-block.scss +43 -24
  49. package/src/theme/component-list-panel.scss +8 -5
  50. package/src/type.ts +77 -50
  51. package/src/utils/editor.ts +9 -1
  52. package/src/utils/index.ts +1 -0
  53. package/src/utils/props.ts +2 -2
  54. package/src/utils/scroll-viewer.ts +18 -2
  55. package/src/utils/stage.ts +4 -3
  56. package/types/Editor.vue.d.ts +47 -27
  57. package/types/components/CodeDraftEditor.vue.d.ts +56 -0
  58. package/types/components/ContentMenu.vue.d.ts +11 -87
  59. package/types/components/FunctionEditor.vue.d.ts +43 -0
  60. package/types/components/Icon.vue.d.ts +4 -50
  61. package/types/{layouts → components}/Layout.vue.d.ts +12 -1
  62. package/types/components/ScrollBar.vue.d.ts +7 -65
  63. package/types/components/ScrollViewer.vue.d.ts +45 -1
  64. package/types/components/ToolButton.vue.d.ts +12 -78
  65. package/types/fields/Code.vue.d.ts +11 -77
  66. package/types/fields/CodeLink.vue.d.ts +12 -82
  67. package/types/fields/CodeSelect.vue.d.ts +13 -77
  68. package/types/fields/UISelect.vue.d.ts +7 -65
  69. package/types/index.d.ts +1 -0
  70. package/types/layouts/AddPageBox.vue.d.ts +1 -43
  71. package/types/layouts/CodeEditor.vue.d.ts +22 -130
  72. package/types/layouts/NavMenu.vue.d.ts +9 -69
  73. package/types/layouts/sidebar/LayerMenu.vue.d.ts +16 -48
  74. package/types/layouts/sidebar/LayerPanel.vue.d.ts +24 -7
  75. package/types/layouts/sidebar/Sidebar.vue.d.ts +10 -5
  76. package/types/layouts/sidebar/code-block/CodeBlockEditor.vue.d.ts +1 -1
  77. package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +6 -5
  78. package/types/layouts/workspace/Breadcrumb.vue.d.ts +1 -43
  79. package/types/layouts/workspace/Stage.vue.d.ts +15 -43
  80. package/types/layouts/workspace/ViewerMenu.vue.d.ts +11 -66
  81. package/types/layouts/workspace/Workspace.vue.d.ts +23 -5
  82. package/types/services/BaseService.d.ts +2 -1
  83. package/types/services/codeBlock.d.ts +57 -36
  84. package/types/services/componentList.d.ts +1 -0
  85. package/types/services/editor.d.ts +5 -6
  86. package/types/services/events.d.ts +1 -0
  87. package/types/services/history.d.ts +5 -15
  88. package/types/services/props.d.ts +3 -2
  89. package/types/services/ui.d.ts +2 -1
  90. package/types/type.d.ts +65 -48
  91. package/types/utils/editor.d.ts +1 -0
  92. package/types/utils/index.d.ts +1 -0
  93. package/types/utils/props.d.ts +1 -1
  94. package/types/utils/scroll-viewer.d.ts +5 -0
  95. package/dist/tmagic-editor.mjs.map +0 -1
  96. package/dist/tmagic-editor.umd.js.map +0 -1
  97. package/src/layouts/sidebar/TabPane.vue +0 -118
  98. package/types/layouts/sidebar/TabPane.vue.d.ts +0 -82
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
- "version": "1.2.0-beta.9",
2
+ "version": "1.2.0",
3
3
  "name": "@tmagic/editor",
4
+ "type": "module",
4
5
  "sideEffects": [
5
6
  "dist/*",
6
7
  "src/theme/*"
7
8
  ],
8
- "main": "dist/tmagic-editor.umd.js",
9
- "module": "dist/tmagic-editor.mjs",
9
+ "main": "dist/tmagic-editor.umd.cjs",
10
+ "module": "dist/tmagic-editor.js",
10
11
  "style": "dist/style.css",
11
12
  "types": "types/index.d.ts",
12
13
  "exports": {
13
14
  ".": {
14
- "import": "./dist/tmagic-editor.mjs",
15
- "require": "./dist/tmagic-editor.umd.js"
15
+ "import": "./dist/tmagic-editor.js",
16
+ "require": "./dist/tmagic-editor.umd.cjs"
16
17
  },
17
18
  "./dist/style.css": {
18
19
  "import": "./dist/style.css",
@@ -45,12 +46,12 @@
45
46
  "dependencies": {
46
47
  "@babel/core": "^7.18.0",
47
48
  "@element-plus/icons-vue": "^2.0.9",
48
- "@tmagic/core": "1.2.0-beta.9",
49
- "@tmagic/design": "1.2.0-beta.9",
50
- "@tmagic/form": "1.2.0-beta.9",
51
- "@tmagic/schema": "1.2.0-beta.9",
52
- "@tmagic/stage": "1.2.0-beta.9",
53
- "@tmagic/utils": "1.2.0-beta.9",
49
+ "@tmagic/core": "1.2.0",
50
+ "@tmagic/design": "1.2.0",
51
+ "@tmagic/form": "1.2.0",
52
+ "@tmagic/schema": "1.2.0",
53
+ "@tmagic/stage": "1.2.0",
54
+ "@tmagic/utils": "1.2.0",
54
55
  "buffer": "^6.0.3",
55
56
  "color": "^3.1.3",
56
57
  "events": "^3.3.0",
@@ -62,8 +63,8 @@
62
63
  "vue": "^3.2.37"
63
64
  },
64
65
  "peerDependencies": {
65
- "@tmagic/design": "1.2.0-beta.9",
66
- "@tmagic/form": "1.2.0-beta.9",
66
+ "@tmagic/design": "1.2.0",
67
+ "@tmagic/form": "1.2.0",
67
68
  "monaco-editor": "^0.34.0",
68
69
  "vue": "^3.2.37"
69
70
  },
@@ -79,6 +80,7 @@
79
80
  "sass": "^1.35.1",
80
81
  "typescript": "^4.7.4",
81
82
  "vite": "^3.1.3",
82
- "vue-tsc": "^1.0.8"
83
+ "vite-plugin-vue-setup-extend": "^0.4.0",
84
+ "vue-tsc": "^1.0.11"
83
85
  }
84
86
  }
package/src/Editor.vue CHANGED
@@ -1,12 +1,12 @@
1
1
  <template>
2
- <framework :code-options="codeOptions">
2
+ <Framework :code-options="codeOptions">
3
3
  <template #nav>
4
- <slot name="nav" :editorService="editorService"><nav-menu :data="menu"></nav-menu></slot>
4
+ <slot name="nav" :editorService="editorService"><TMagicNavMenu :data="menu"></TMagicNavMenu></slot>
5
5
  </template>
6
6
 
7
7
  <template #sidebar>
8
8
  <slot name="sidebar" :editorService="editorService">
9
- <sidebar :data="sidebar">
9
+ <Sidebar :data="sidebar" :layer-content-menu="layerContentMenu">
10
10
  <template #layer-panel-header>
11
11
  <slot name="layer-panel-header"></slot>
12
12
  </template>
@@ -34,33 +34,33 @@
34
34
  <template #code-block-edit-panel-header="{ id }">
35
35
  <slot name="code-block-edit-panel-header" :id="id"></slot>
36
36
  </template>
37
- </sidebar>
37
+ </Sidebar>
38
38
  </slot>
39
39
  </template>
40
40
 
41
41
  <template #workspace>
42
42
  <slot name="workspace" :editorService="editorService">
43
- <workspace>
43
+ <Workspace :stage-content-menu="stageContentMenu">
44
44
  <template #stage><slot name="stage"></slot></template>
45
45
  <template #workspace-content><slot name="workspace-content" :editorService="editorService"></slot></template>
46
46
  <template #page-bar-title="{ page }"><slot name="page-bar-title" :page="page"></slot></template>
47
47
  <template #page-bar-popover="{ page }"><slot name="page-bar-popover" :page="page"></slot></template>
48
- </workspace>
48
+ </Workspace>
49
49
  </slot>
50
50
  </template>
51
51
 
52
52
  <template #props-panel>
53
53
  <slot name="props-panel">
54
- <props-panel @mounted="(instance: any) => $emit('props-panel-mounted', instance)">
54
+ <PropsPanel @mounted="(instance: any) => $emit('props-panel-mounted', instance)">
55
55
  <template #props-panel-header>
56
56
  <slot name="props-panel-header"></slot>
57
57
  </template>
58
- </props-panel>
58
+ </PropsPanel>
59
59
  </slot>
60
60
  </template>
61
61
 
62
62
  <template #empty><slot name="empty" :editorService="editorService"></slot></template>
63
- </framework>
63
+ </Framework>
64
64
  </template>
65
65
 
66
66
  <script lang="ts">
@@ -69,8 +69,13 @@ import { defineComponent, onUnmounted, PropType, provide, reactive, toRaw, watch
69
69
  import { EventOption } from '@tmagic/core';
70
70
  import type { FormConfig } from '@tmagic/form';
71
71
  import type { MApp, MNode } from '@tmagic/schema';
72
- import type StageCore from '@tmagic/stage';
73
- import { CONTAINER_HIGHLIGHT_CLASS, ContainerHighlightType, MoveableOptions } from '@tmagic/stage';
72
+ import StageCore, {
73
+ CONTAINER_HIGHLIGHT_CLASS_NAME,
74
+ ContainerHighlightType,
75
+ CustomizeMoveableOptionsCallbackConfig,
76
+ MoveableOptions,
77
+ UpdateDragEl,
78
+ } from '@tmagic/stage';
74
79
 
75
80
  import Framework from './layouts/Framework.vue';
76
81
  import NavMenu from './layouts/NavMenu.vue';
@@ -91,7 +96,7 @@ export default defineComponent({
91
96
  name: 'm-editor',
92
97
 
93
98
  components: {
94
- NavMenu,
99
+ TMagicNavMenu: NavMenu,
95
100
  Sidebar,
96
101
  Workspace,
97
102
  PropsPanel,
@@ -117,25 +122,27 @@ export default defineComponent({
117
122
  type: Object as PropType<SideBarData>,
118
123
  },
119
124
 
125
+ /** 顶部工具栏配置 */
126
+ menu: {
127
+ type: Object as PropType<MenuBarData>,
128
+ default: () => ({ left: [], right: [] }),
129
+ },
130
+
131
+ /** 组件树右键菜单 */
120
132
  layerContentMenu: {
121
133
  type: Array as PropType<(MenuButton | MenuComponent)[]>,
122
134
  default: () => [],
123
135
  },
124
136
 
137
+ /** 画布右键菜单 */
125
138
  stageContentMenu: {
126
139
  type: Array as PropType<(MenuButton | MenuComponent)[]>,
127
140
  default: () => [],
128
141
  },
129
142
 
130
- /** 顶部工具栏配置 */
131
- menu: {
132
- type: Object as PropType<MenuBarData>,
133
- default: () => ({ left: [], right: [] }),
134
- },
135
-
136
143
  /** 中间工作区域中画布渲染的内容 */
137
144
  render: {
138
- type: Function as PropType<() => HTMLDivElement>,
145
+ type: Function as PropType<(stage: StageCore) => HTMLDivElement | Promise<HTMLDivElement>>,
139
146
  },
140
147
 
141
148
  /** 中间工作区域中画布通过iframe渲染时的页面url */
@@ -158,13 +165,15 @@ export default defineComponent({
158
165
 
159
166
  /** 组件联动事件选项列表 */
160
167
  eventMethodList: {
161
- type: Object,
168
+ type: Object as PropType<Record<string, { events: EventOption[]; methods: EventOption[] }>>,
162
169
  default: () => ({}),
163
170
  },
164
171
 
165
172
  /** 画布中组件选中框的移动范围 */
166
173
  moveableOptions: {
167
- type: [Object, Function] as PropType<MoveableOptions | ((core?: StageCore) => MoveableOptions)>,
174
+ type: [Object, Function] as PropType<
175
+ MoveableOptions | ((config?: CustomizeMoveableOptionsCallbackConfig) => MoveableOptions)
176
+ >,
168
177
  },
169
178
 
170
179
  /** 编辑器初始化时默认选中的组件ID */
@@ -184,7 +193,7 @@ export default defineComponent({
184
193
 
185
194
  containerHighlightClassName: {
186
195
  type: String,
187
- default: CONTAINER_HIGHLIGHT_CLASS,
196
+ default: CONTAINER_HIGHLIGHT_CLASS_NAME,
188
197
  },
189
198
 
190
199
  containerHighlightDuration: {
@@ -207,24 +216,40 @@ export default defineComponent({
207
216
  },
208
217
 
209
218
  updateDragEl: {
210
- type: Function as PropType<(el: HTMLDivElement, target: HTMLElement) => void>,
219
+ type: Function as PropType<UpdateDragEl>,
220
+ },
221
+
222
+ disabledDragStart: {
223
+ type: Boolean,
211
224
  },
212
225
  },
213
226
 
214
227
  emits: ['props-panel-mounted', 'update:modelValue'],
215
228
 
216
229
  setup(props, { emit }) {
217
- editorService.on('root-change', (value) => {
218
- const node = editorService.get<MNode | null>('node');
219
- const nodeId = node?.id || props.defaultSelected;
220
- if (nodeId && node !== value) {
221
- editorService.select(nodeId);
222
- } else {
230
+ const rootChangeHandler = (value: MApp, preValue?: MApp | null) => {
231
+ const nodeId = editorService.get<MNode | null>('node')?.id || props.defaultSelected;
232
+ let node;
233
+ if (nodeId) {
234
+ node = editorService.getNodeById(nodeId);
235
+ }
236
+
237
+ if (node && node !== value) {
238
+ editorService.select(node.id);
239
+ } else if (value?.items?.length) {
240
+ editorService.select(value.items[0]);
241
+ } else if (value?.id) {
223
242
  editorService.set('nodes', [value]);
243
+ editorService.set('parent', null);
244
+ editorService.set('page', null);
224
245
  }
225
246
 
226
- emit('update:modelValue', toRaw(editorService.get('root')));
227
- });
247
+ if (toRaw(value) !== toRaw(preValue)) {
248
+ emit('update:modelValue', value);
249
+ }
250
+ };
251
+
252
+ editorService.on('root-change', rootChangeHandler);
228
253
 
229
254
  // 初始值变化,重新设置节点信息
230
255
  watch(
@@ -297,13 +322,14 @@ export default defineComponent({
297
322
  );
298
323
 
299
324
  onUnmounted(() => {
300
- editorService.destroy();
301
- historyService.destroy();
302
- propsService.destroy();
303
- uiService.destroy();
304
- componentListService.destroy();
305
- storageService.destroy();
306
- codeBlockService.destroy();
325
+ editorService.resetState();
326
+ historyService.resetState();
327
+ propsService.resetState();
328
+ uiService.resetState();
329
+ componentListService.resetState();
330
+ codeBlockService.resetState();
331
+
332
+ editorService.off('root-change', rootChangeHandler);
307
333
  });
308
334
 
309
335
  const services: Services = {
@@ -319,8 +345,7 @@ export default defineComponent({
319
345
 
320
346
  provide('services', services);
321
347
 
322
- provide('layerContentMenu', props.layerContentMenu);
323
- provide('stageContentMenu', props.stageContentMenu);
348
+ provide('codeOptions', props.codeOptions);
324
349
  provide(
325
350
  'stageOptions',
326
351
  reactive({
@@ -334,6 +359,7 @@ export default defineComponent({
334
359
  containerHighlightClassName: props.containerHighlightClassName,
335
360
  containerHighlightDuration: props.containerHighlightDuration,
336
361
  containerHighlightType: props.containerHighlightType,
362
+ disabledDragStart: props.disabledDragStart,
337
363
  }),
338
364
  );
339
365
 
@@ -0,0 +1,145 @@
1
+ <template>
2
+ <div class="m-editor-wrapper" :class="isFullScreen ? 'fullScreen' : 'normal'">
3
+ <magic-code-editor
4
+ ref="codeEditor"
5
+ class="m-editor-container"
6
+ :init-values="`${codeContent}`"
7
+ @save="saveCodeDraft"
8
+ :language="language"
9
+ :options="codeOptions"
10
+ ></magic-code-editor>
11
+ <div class="m-editor-content-bottom" v-if="editable">
12
+ <TMagicButton type="primary" class="button" @click="toggleFullScreen">
13
+ {{ isFullScreen ? '退出全屏' : '全屏' }}</TMagicButton
14
+ >
15
+ <TMagicButton type="primary" class="button" @click="saveCode">保存</TMagicButton>
16
+ <TMagicButton type="primary" class="button" @click="close">关闭</TMagicButton>
17
+ </div>
18
+ <div class="m-editor-content-bottom" v-else>
19
+ <TMagicButton type="primary" class="button" @click="toggleFullScreen">
20
+ {{ isFullScreen ? '退出全屏' : '全屏' }}</TMagicButton
21
+ >
22
+ <TMagicButton type="primary" class="button" @click="close">关闭</TMagicButton>
23
+ </div>
24
+ </div>
25
+ </template>
26
+ <script lang="ts" setup name="MEditorCodeDraftEditor">
27
+ import { computed, inject, ref, watchEffect } from 'vue';
28
+ import type * as monaco from 'monaco-editor';
29
+
30
+ import { TMagicButton, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
31
+ import { Id } from '@tmagic/schema';
32
+ import { datetimeFormatter } from '@tmagic/utils';
33
+
34
+ import MagicCodeEditor from '../layouts/CodeEditor.vue';
35
+ import type { Services } from '../type';
36
+
37
+ const props = withDefaults(
38
+ defineProps<{
39
+ /** 代码id */
40
+ id: Id;
41
+ /** 代码内容 */
42
+ content: string;
43
+ /** 是否可编辑 */
44
+ editable?: boolean;
45
+ /** 是否自动保存草稿 */
46
+ autoSaveDraft?: boolean;
47
+ /** 编辑器参数 */
48
+ codeOptions?: Object;
49
+ /** 编辑器语言 */
50
+ language?: string;
51
+ }>(),
52
+ {
53
+ editable: true,
54
+ autoSaveDraft: true,
55
+ },
56
+ );
57
+ const emit = defineEmits(['save', 'close', 'saveAndClose']);
58
+
59
+ const services = inject<Services>('services');
60
+
61
+ const codeContent = ref<string>('');
62
+ const editorContent = ref<string>('');
63
+ const codeEditor = ref<InstanceType<typeof MagicCodeEditor>>();
64
+ // 原始代码内容
65
+ const originCodeContent = ref<string>('');
66
+ const isFullScreen = ref<boolean>(false);
67
+
68
+ const codeOptions = computed(() => ({
69
+ ...props.codeOptions,
70
+ readOnly: !props.editable,
71
+ }));
72
+
73
+ watchEffect(() => {
74
+ codeContent.value = props.content;
75
+ if (!originCodeContent.value) {
76
+ // 暂存原始的代码内容
77
+ originCodeContent.value = codeContent.value;
78
+ }
79
+ // 有草稿时展示上次保存的草稿内容
80
+ const codeDraft = services?.codeBlockService.getCodeDraft(props.id);
81
+ if (codeDraft) {
82
+ codeContent.value = codeDraft;
83
+ }
84
+ });
85
+
86
+ // 保存草稿
87
+ const saveCodeDraft = async (codeValue: string) => {
88
+ if (!props.autoSaveDraft) return;
89
+ if (originCodeContent.value === codeValue) {
90
+ // 没修改或改回原样 有草稿的话删除草稿
91
+ services?.codeBlockService.removeCodeDraft(props.id);
92
+ return;
93
+ }
94
+ services?.codeBlockService.setCodeDraft(props.id, codeValue);
95
+ tMagicMessage.success(`代码草稿保存成功 ${datetimeFormatter(new Date())}`);
96
+ };
97
+
98
+ // 保存代码
99
+ const saveCode = (): void => {
100
+ if (!codeEditor.value || !props.editable) return;
101
+ // 代码内容
102
+ editorContent.value = (codeEditor.value.getEditor() as monaco.editor.IStandaloneCodeEditor)?.getValue();
103
+ emit('save', editorContent.value);
104
+ };
105
+
106
+ // 保存并关闭
107
+ const saveAndClose = (): void => {
108
+ if (!codeEditor.value || !props.editable) return;
109
+ // 代码内容
110
+ editorContent.value = (codeEditor.value.getEditor() as monaco.editor.IStandaloneCodeEditor)?.getValue();
111
+ emit('saveAndClose', editorContent.value);
112
+ };
113
+
114
+ // 关闭弹窗
115
+ const close = async (): Promise<void> => {
116
+ const codeDraft = services?.codeBlockService.getCodeDraft(props.id);
117
+ if (codeDraft) {
118
+ tMagicMessageBox
119
+ .confirm('您有代码修改未保存,是否保存后再关闭?', '提示', {
120
+ confirmButtonText: '确认',
121
+ cancelButtonText: '取消',
122
+ type: 'warning',
123
+ })
124
+ .then(async () => {
125
+ // 保存之后再关闭
126
+ saveAndClose();
127
+ })
128
+ .catch(() => {
129
+ // 删除草稿 直接关闭
130
+ services?.codeBlockService.removeCodeDraft(props.id);
131
+ emit('close');
132
+ });
133
+ } else {
134
+ emit('close');
135
+ }
136
+ };
137
+
138
+ // 切换全屏
139
+ const toggleFullScreen = (): void => {
140
+ isFullScreen.value = !isFullScreen.value;
141
+ if (codeEditor.value) {
142
+ codeEditor.value.focus();
143
+ }
144
+ };
145
+ </script>
@@ -22,7 +22,7 @@
22
22
  </div>
23
23
  </template>
24
24
 
25
- <script lang="ts" setup>
25
+ <script lang="ts" setup name="MEditorContentMenu">
26
26
  import { nextTick, onMounted, onUnmounted, ref } from 'vue';
27
27
 
28
28
  import { MenuButton, MenuComponent } from '../type';
@@ -0,0 +1,145 @@
1
+ <template>
2
+ <TMagicCard shadow="never">
3
+ <template #header>
4
+ <div class="code-name-wrapper">
5
+ <div class="code-name-label">代码块名称</div>
6
+ <TMagicInput class="code-name-input" v-model="codeName" :disabled="!editable" />
7
+ </div>
8
+ <div class="code-name-wrapper">
9
+ <div class="code-name-label">参数定义</div>
10
+ <m-form-table
11
+ style="width: 320px"
12
+ :config="tableConfig"
13
+ :model="tableModel"
14
+ :enableToggleMode="false"
15
+ name="params"
16
+ prop="params"
17
+ size="small"
18
+ >
19
+ </m-form-table>
20
+ </div>
21
+ </template>
22
+ <CodeDraftEditor
23
+ :id="id"
24
+ :content="codeContent"
25
+ :editable="editable"
26
+ :autoSaveDraft="autoSaveDraft"
27
+ :codeOptions="codeOptions"
28
+ language="javascript"
29
+ @save="saveCode"
30
+ @saveAndClose="saveAndClose"
31
+ @close="close"
32
+ ></CodeDraftEditor>
33
+ </TMagicCard>
34
+ </template>
35
+ <script lang="ts" setup name="MEditorFunctionEditor">
36
+ import { inject, provide, ref, watchEffect } from 'vue';
37
+
38
+ import { TMagicCard, TMagicInput, tMagicMessage } from '@tmagic/design';
39
+ import { CodeParam, Id } from '@tmagic/schema';
40
+
41
+ import type { Services } from '../type';
42
+
43
+ import CodeDraftEditor from './CodeDraftEditor.vue';
44
+
45
+ const tableConfig = {
46
+ border: true,
47
+ enableFullscreen: false,
48
+ name: 'params',
49
+ maxHeight: '150px',
50
+ items: [
51
+ {
52
+ type: 'text',
53
+ label: '参数名',
54
+ name: 'name',
55
+ },
56
+ ],
57
+ };
58
+
59
+ const props = withDefaults(
60
+ defineProps<{
61
+ id: Id;
62
+ name: string;
63
+ content: string;
64
+ editable?: boolean;
65
+ autoSaveDraft?: boolean;
66
+ codeOptions?: object;
67
+ }>(),
68
+ {
69
+ editable: true,
70
+ autoSaveDraft: true,
71
+ },
72
+ );
73
+
74
+ const emit = defineEmits(['change', 'field-input']);
75
+
76
+ const services = inject<Services>('services');
77
+
78
+ const codeName = ref<string>('');
79
+ const codeContent = ref<string>('');
80
+ const evalRes = ref(true);
81
+
82
+ provide('mForm', {
83
+ $emit: emit,
84
+ setField: () => {},
85
+ });
86
+
87
+ const tableModel = ref<{ params: CodeParam[] }>();
88
+ watchEffect(() => {
89
+ codeName.value = props.name;
90
+ codeContent.value = props.content;
91
+ });
92
+
93
+ const initTableModel = (): void => {
94
+ const codeDsl = services?.codeBlockService.getCodeDslSync();
95
+ if (!codeDsl) return;
96
+ tableModel.value = {
97
+ params: codeDsl[props.id]?.params || [],
98
+ };
99
+ };
100
+
101
+ initTableModel();
102
+
103
+ // 保存前钩子
104
+ const beforeSave = (codeValue: string): boolean => {
105
+ try {
106
+ // eval检测js代码是否存在语法错误
107
+ // eslint-disable-next-line no-eval
108
+ eval(codeValue);
109
+ return true;
110
+ } catch (e: any) {
111
+ tMagicMessage.error(e.stack);
112
+ return false;
113
+ }
114
+ };
115
+
116
+ // 保存代码
117
+ const saveCode = async (codeValue: string): Promise<void> => {
118
+ if (!props.editable) return;
119
+ evalRes.value = beforeSave(codeValue);
120
+ if (evalRes.value) {
121
+ // 存入dsl
122
+ await services?.codeBlockService.setCodeDslById(props.id, {
123
+ name: codeName.value,
124
+ content: codeValue,
125
+ params: tableModel.value?.params || [],
126
+ });
127
+ tMagicMessage.success('代码保存成功');
128
+ // 删除草稿
129
+ services?.codeBlockService.removeCodeDraft(props.id);
130
+ }
131
+ };
132
+
133
+ // 保存并关闭
134
+ const saveAndClose = async (codeValue: string): Promise<void> => {
135
+ await saveCode(codeValue);
136
+ if (evalRes.value) {
137
+ close();
138
+ }
139
+ };
140
+
141
+ // 关闭弹窗
142
+ const close = (): void => {
143
+ services?.codeBlockService.setCodeEditorShowStatus(false);
144
+ };
145
+ </script>
@@ -7,7 +7,7 @@
7
7
  <TMagicIcon v-else class="magic-editor-icon"><component :is="toRaw(icon)"></component></TMagicIcon>
8
8
  </template>
9
9
 
10
- <script lang="ts" setup>
10
+ <script lang="ts" setup name="MEditorIcon">
11
11
  import { toRaw } from 'vue';
12
12
  import { Edit } from '@element-plus/icons-vue';
13
13