@tmagic/editor 1.2.0-beta.2 → 1.2.0-beta.21
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.
- package/dist/style.css +41 -28
- package/dist/{tmagic-editor.mjs → tmagic-editor.js} +1693 -1272
- package/dist/tmagic-editor.js.map +1 -0
- package/dist/{tmagic-editor.umd.js → tmagic-editor.umd.cjs} +1700 -1274
- package/dist/tmagic-editor.umd.cjs.map +1 -0
- package/package.json +16 -14
- package/src/Editor.vue +54 -37
- package/src/components/CodeDraftEditor.vue +145 -0
- package/src/components/ContentMenu.vue +4 -4
- package/src/components/FunctionEditor.vue +145 -0
- package/src/components/Icon.vue +7 -5
- package/src/components/Layout.vue +149 -0
- package/src/components/ScrollBar.vue +1 -1
- package/src/components/ScrollViewer.vue +10 -1
- package/src/components/ToolButton.vue +30 -15
- package/src/fields/Code.vue +1 -1
- package/src/fields/CodeLink.vue +1 -1
- package/src/fields/CodeSelect.vue +89 -110
- package/src/fields/UISelect.vue +9 -8
- package/src/index.ts +1 -0
- package/src/layouts/AddPageBox.vue +3 -2
- package/src/layouts/CodeEditor.vue +2 -3
- package/src/layouts/Framework.vue +62 -40
- package/src/layouts/NavMenu.vue +1 -1
- package/src/layouts/PropsPanel.vue +11 -13
- package/src/layouts/Resizer.vue +1 -1
- package/src/layouts/sidebar/ComponentListPanel.vue +15 -13
- package/src/layouts/sidebar/LayerMenu.vue +9 -7
- package/src/layouts/sidebar/LayerPanel.vue +277 -177
- package/src/layouts/sidebar/Sidebar.vue +113 -27
- package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +34 -85
- package/src/layouts/sidebar/code-block/CodeBlockList.vue +55 -89
- package/src/layouts/workspace/Breadcrumb.vue +32 -0
- package/src/layouts/workspace/PageBar.vue +12 -11
- package/src/layouts/workspace/PageBarScrollContainer.vue +1 -1
- package/src/layouts/workspace/Stage.vue +26 -9
- package/src/layouts/workspace/ViewerMenu.vue +11 -9
- package/src/layouts/workspace/Workspace.vue +10 -3
- package/src/services/BaseService.ts +6 -1
- package/src/services/codeBlock.ts +124 -125
- package/src/services/componentList.ts +6 -1
- package/src/services/editor.ts +43 -19
- package/src/services/events.ts +6 -1
- package/src/services/history.ts +7 -16
- package/src/services/props.ts +7 -2
- package/src/services/storage.ts +1 -0
- package/src/services/ui.ts +12 -0
- package/src/theme/breadcrumb.scss +6 -0
- package/src/theme/code-block.scss +30 -21
- package/src/theme/component-list-panel.scss +3 -7
- package/src/theme/layer-panel.scss +7 -2
- package/src/theme/theme.scss +1 -0
- package/src/type.ts +76 -50
- package/src/utils/editor.ts +9 -1
- package/src/utils/index.ts +1 -0
- package/src/utils/props.ts +2 -2
- package/src/utils/scroll-viewer.ts +18 -2
- package/src/utils/stage.ts +9 -2
- package/types/Editor.vue.d.ts +42 -29
- package/types/components/CodeDraftEditor.vue.d.ts +148 -0
- package/types/components/ContentMenu.vue.d.ts +1 -3
- package/types/components/FunctionEditor.vue.d.ts +120 -0
- package/types/components/Icon.vue.d.ts +1 -3
- package/types/{layouts → components}/Layout.vue.d.ts +12 -1
- package/types/components/ScrollBar.vue.d.ts +1 -3
- package/types/components/ScrollViewer.vue.d.ts +45 -1
- package/types/components/ToolButton.vue.d.ts +1 -3
- package/types/fields/Code.vue.d.ts +1 -3
- package/types/fields/CodeLink.vue.d.ts +1 -3
- package/types/fields/CodeSelect.vue.d.ts +10 -12
- package/types/fields/UISelect.vue.d.ts +1 -3
- package/types/index.d.ts +1 -0
- package/types/layouts/AddPageBox.vue.d.ts +1 -3
- package/types/layouts/CodeEditor.vue.d.ts +6 -15
- package/types/layouts/NavMenu.vue.d.ts +1 -3
- package/types/layouts/sidebar/LayerMenu.vue.d.ts +25 -9
- package/types/layouts/sidebar/LayerPanel.vue.d.ts +38 -886
- package/types/layouts/sidebar/Sidebar.vue.d.ts +10 -5
- package/types/layouts/sidebar/code-block/CodeBlockEditor.vue.d.ts +1 -1
- package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +6 -5
- package/types/layouts/{sidebar/TabPane.vue.d.ts → workspace/Breadcrumb.vue.d.ts} +5 -43
- package/types/layouts/workspace/Stage.vue.d.ts +25 -8
- package/types/layouts/workspace/ViewerMenu.vue.d.ts +6 -3
- package/types/layouts/workspace/Workspace.vue.d.ts +23 -5
- package/types/services/BaseService.d.ts +2 -1
- package/types/services/codeBlock.d.ts +57 -36
- package/types/services/componentList.d.ts +1 -0
- package/types/services/editor.d.ts +5 -6
- package/types/services/events.d.ts +1 -0
- package/types/services/history.d.ts +5 -15
- package/types/services/props.d.ts +3 -2
- package/types/services/ui.d.ts +2 -1
- package/types/type.d.ts +64 -48
- package/types/utils/editor.d.ts +1 -0
- package/types/utils/index.d.ts +1 -0
- package/types/utils/props.d.ts +1 -1
- package/types/utils/scroll-viewer.d.ts +5 -0
- package/dist/tmagic-editor.mjs.map +0 -1
- package/dist/tmagic-editor.umd.js.map +0 -1
- package/src/layouts/Layout.vue +0 -100
- package/src/layouts/sidebar/TabPane.vue +0 -116
package/package.json
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.2.0-beta.
|
|
2
|
+
"version": "1.2.0-beta.21",
|
|
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.
|
|
9
|
-
"module": "dist/tmagic-editor.
|
|
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.
|
|
15
|
-
"require": "./dist/tmagic-editor.umd.
|
|
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,14 +46,14 @@
|
|
|
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.
|
|
49
|
-
"@tmagic/
|
|
50
|
-
"@tmagic/
|
|
51
|
-
"@tmagic/
|
|
52
|
-
"@tmagic/
|
|
49
|
+
"@tmagic/core": "1.2.0-beta.21",
|
|
50
|
+
"@tmagic/design": "1.2.0-beta.21",
|
|
51
|
+
"@tmagic/form": "1.2.0-beta.21",
|
|
52
|
+
"@tmagic/schema": "1.2.0-beta.21",
|
|
53
|
+
"@tmagic/stage": "1.2.0-beta.21",
|
|
54
|
+
"@tmagic/utils": "1.2.0-beta.21",
|
|
53
55
|
"buffer": "^6.0.3",
|
|
54
56
|
"color": "^3.1.3",
|
|
55
|
-
"element-plus": "^2.2.17",
|
|
56
57
|
"events": "^3.3.0",
|
|
57
58
|
"gesto": "^1.7.0",
|
|
58
59
|
"keycon": "^1.1.2",
|
|
@@ -62,8 +63,8 @@
|
|
|
62
63
|
"vue": "^3.2.37"
|
|
63
64
|
},
|
|
64
65
|
"peerDependencies": {
|
|
65
|
-
"@tmagic/
|
|
66
|
-
"
|
|
66
|
+
"@tmagic/design": "1.2.0-beta.21",
|
|
67
|
+
"@tmagic/form": "1.2.0-beta.21",
|
|
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-
|
|
83
|
+
"vite-plugin-vue-setup-extend": "^0.4.0",
|
|
84
|
+
"vue-tsc": "^1.0.10"
|
|
83
85
|
}
|
|
84
86
|
}
|
package/src/Editor.vue
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<Framework :code-options="codeOptions">
|
|
3
3
|
<template #nav>
|
|
4
|
-
<slot name="nav" :editorService="editorService"><
|
|
4
|
+
<slot name="nav" :editorService="editorService"><NavMenu :data="menu"></NavMenu></slot>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<template #sidebar>
|
|
8
8
|
<slot name="sidebar" :editorService="editorService">
|
|
9
|
-
<
|
|
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
|
-
</
|
|
37
|
+
</Sidebar>
|
|
38
38
|
</slot>
|
|
39
39
|
</template>
|
|
40
40
|
|
|
41
41
|
<template #workspace>
|
|
42
42
|
<slot name="workspace" :editorService="editorService">
|
|
43
|
-
<
|
|
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
|
-
</
|
|
48
|
+
</Workspace>
|
|
49
49
|
</slot>
|
|
50
50
|
</template>
|
|
51
51
|
|
|
52
52
|
<template #props-panel>
|
|
53
53
|
<slot name="props-panel">
|
|
54
|
-
<
|
|
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
|
-
</
|
|
58
|
+
</PropsPanel>
|
|
59
59
|
</slot>
|
|
60
60
|
</template>
|
|
61
61
|
|
|
62
62
|
<template #empty><slot name="empty" :editorService="editorService"></slot></template>
|
|
63
|
-
</
|
|
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
|
|
73
|
-
|
|
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';
|
|
@@ -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<
|
|
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:
|
|
196
|
+
default: CONTAINER_HIGHLIGHT_CLASS_NAME,
|
|
188
197
|
},
|
|
189
198
|
|
|
190
199
|
containerHighlightDuration: {
|
|
@@ -207,7 +216,7 @@ export default defineComponent({
|
|
|
207
216
|
},
|
|
208
217
|
|
|
209
218
|
updateDragEl: {
|
|
210
|
-
type: Function as PropType<
|
|
219
|
+
type: Function as PropType<UpdateDragEl>,
|
|
211
220
|
},
|
|
212
221
|
},
|
|
213
222
|
|
|
@@ -215,15 +224,25 @@ export default defineComponent({
|
|
|
215
224
|
|
|
216
225
|
setup(props, { emit }) {
|
|
217
226
|
editorService.on('root-change', (value) => {
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
if (nodeId
|
|
221
|
-
editorService.
|
|
222
|
-
}
|
|
227
|
+
const nodeId = editorService.get<MNode | null>('node')?.id || props.defaultSelected;
|
|
228
|
+
let node;
|
|
229
|
+
if (nodeId) {
|
|
230
|
+
node = editorService.getNodeById(nodeId);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (node && node !== value) {
|
|
234
|
+
editorService.select(node.id);
|
|
235
|
+
} else if (value?.items?.length) {
|
|
236
|
+
editorService.select(value.items[0]);
|
|
237
|
+
} else if (value?.id) {
|
|
223
238
|
editorService.set('nodes', [value]);
|
|
239
|
+
editorService.set('parent', null);
|
|
240
|
+
editorService.set('page', null);
|
|
224
241
|
}
|
|
225
242
|
|
|
226
|
-
|
|
243
|
+
if (toRaw(value) !== toRaw(editorService.get('root'))) {
|
|
244
|
+
emit('update:modelValue', value);
|
|
245
|
+
}
|
|
227
246
|
});
|
|
228
247
|
|
|
229
248
|
// 初始值变化,重新设置节点信息
|
|
@@ -297,13 +316,12 @@ export default defineComponent({
|
|
|
297
316
|
);
|
|
298
317
|
|
|
299
318
|
onUnmounted(() => {
|
|
300
|
-
editorService.
|
|
301
|
-
historyService.
|
|
302
|
-
propsService.
|
|
303
|
-
uiService.
|
|
304
|
-
componentListService.
|
|
305
|
-
|
|
306
|
-
codeBlockService.destroy();
|
|
319
|
+
editorService.resetState();
|
|
320
|
+
historyService.resetState();
|
|
321
|
+
propsService.resetState();
|
|
322
|
+
uiService.resetState();
|
|
323
|
+
componentListService.resetState();
|
|
324
|
+
codeBlockService.resetState();
|
|
307
325
|
});
|
|
308
326
|
|
|
309
327
|
const services: Services = {
|
|
@@ -319,8 +337,7 @@ export default defineComponent({
|
|
|
319
337
|
|
|
320
338
|
provide('services', services);
|
|
321
339
|
|
|
322
|
-
provide('
|
|
323
|
-
provide('stageContentMenu', props.stageContentMenu);
|
|
340
|
+
provide('codeOptions', props.codeOptions);
|
|
324
341
|
provide(
|
|
325
342
|
'stageOptions',
|
|
326
343
|
reactive({
|
|
@@ -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>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div v-if="menuData.length
|
|
2
|
+
<div v-if="menuData.length" v-show="visible" class="magic-editor-content-menu" ref="menu" :style="menuStyle">
|
|
3
3
|
<div>
|
|
4
|
-
<
|
|
4
|
+
<ToolButton
|
|
5
5
|
v-for="(item, index) in menuData"
|
|
6
6
|
event-type="mouseup"
|
|
7
7
|
:data="item"
|
|
8
8
|
:key="index"
|
|
9
9
|
@mouseup="hide"
|
|
10
10
|
@mouseenter="showSubMenu(item)"
|
|
11
|
-
></
|
|
11
|
+
></ToolButton>
|
|
12
12
|
</div>
|
|
13
13
|
<teleport to="body">
|
|
14
14
|
<content-menu
|
|
@@ -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>
|
package/src/components/Icon.vue
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
2
|
+
<TMagicIcon v-if="!icon" class="magic-editor-icon"><Edit></Edit></TMagicIcon>
|
|
3
|
+
<TMagicIcon v-else-if="typeof icon === 'string' && icon.startsWith('http')" class="magic-editor-icon"
|
|
4
4
|
><img :src="icon"
|
|
5
|
-
/></
|
|
5
|
+
/></TMagicIcon>
|
|
6
6
|
<i v-else-if="typeof icon === 'string'" class="magic-editor-icon" :class="icon"></i>
|
|
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
|
|
|
14
|
+
import { TMagicIcon } from '@tmagic/design';
|
|
15
|
+
|
|
14
16
|
defineProps<{
|
|
15
17
|
icon?: any;
|
|
16
18
|
}>();
|