@tmagic/editor 1.2.0-beta.8 → 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.
- package/dist/style.css +59 -35
- package/dist/{tmagic-editor.mjs → tmagic-editor.js} +1473 -1161
- package/dist/tmagic-editor.js.map +1 -0
- package/dist/{tmagic-editor.umd.js → tmagic-editor.umd.cjs} +1483 -1166
- package/dist/tmagic-editor.umd.cjs.map +1 -0
- package/package.json +16 -14
- package/src/Editor.vue +66 -40
- package/src/components/CodeDraftEditor.vue +145 -0
- package/src/components/ContentMenu.vue +2 -2
- package/src/components/FunctionEditor.vue +145 -0
- package/src/components/Icon.vue +1 -1
- package/src/{layouts → components}/Layout.vue +54 -15
- package/src/components/ScrollBar.vue +1 -1
- package/src/components/ScrollViewer.vue +10 -1
- package/src/components/ToolButton.vue +1 -1
- package/src/fields/Code.vue +1 -1
- package/src/fields/CodeLink.vue +1 -1
- package/src/fields/CodeSelect.vue +84 -110
- package/src/fields/UISelect.vue +1 -1
- package/src/index.ts +1 -0
- package/src/layouts/AddPageBox.vue +1 -1
- package/src/layouts/CodeEditor.vue +2 -3
- package/src/layouts/Framework.vue +2 -2
- package/src/layouts/NavMenu.vue +2 -2
- package/src/layouts/PropsPanel.vue +13 -6
- package/src/layouts/Resizer.vue +1 -1
- package/src/layouts/sidebar/ComponentListPanel.vue +1 -1
- package/src/layouts/sidebar/LayerMenu.vue +9 -7
- package/src/layouts/sidebar/LayerPanel.vue +127 -174
- package/src/layouts/sidebar/Sidebar.vue +110 -26
- package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +27 -83
- package/src/layouts/sidebar/code-block/CodeBlockList.vue +90 -122
- package/src/layouts/workspace/Breadcrumb.vue +1 -1
- package/src/layouts/workspace/PageBar.vue +1 -1
- 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 +7 -3
- package/src/services/BaseService.ts +10 -1
- package/src/services/codeBlock.ts +124 -125
- package/src/services/componentList.ts +6 -1
- package/src/services/editor.ts +54 -18
- 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/code-block.scss +43 -24
- package/src/theme/component-list-panel.scss +8 -5
- package/src/type.ts +77 -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 +4 -3
- package/types/Editor.vue.d.ts +47 -27
- package/types/components/CodeDraftEditor.vue.d.ts +56 -0
- package/types/components/ContentMenu.vue.d.ts +11 -87
- package/types/components/FunctionEditor.vue.d.ts +43 -0
- package/types/components/Icon.vue.d.ts +4 -50
- package/types/{layouts → components}/Layout.vue.d.ts +12 -1
- package/types/components/ScrollBar.vue.d.ts +7 -65
- package/types/components/ScrollViewer.vue.d.ts +45 -1
- package/types/components/ToolButton.vue.d.ts +12 -78
- package/types/fields/Code.vue.d.ts +11 -77
- package/types/fields/CodeLink.vue.d.ts +12 -82
- package/types/fields/CodeSelect.vue.d.ts +13 -77
- package/types/fields/UISelect.vue.d.ts +7 -65
- package/types/index.d.ts +1 -0
- package/types/layouts/AddPageBox.vue.d.ts +1 -43
- package/types/layouts/CodeEditor.vue.d.ts +22 -130
- package/types/layouts/NavMenu.vue.d.ts +9 -69
- package/types/layouts/sidebar/LayerMenu.vue.d.ts +16 -48
- package/types/layouts/sidebar/LayerPanel.vue.d.ts +24 -7
- 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/workspace/Breadcrumb.vue.d.ts +1 -43
- package/types/layouts/workspace/Stage.vue.d.ts +15 -43
- package/types/layouts/workspace/ViewerMenu.vue.d.ts +11 -66
- 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 +65 -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/sidebar/TabPane.vue +0 -118
- 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
|
|
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.
|
|
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,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
|
|
49
|
-
"@tmagic/design": "1.2.0
|
|
50
|
-
"@tmagic/form": "1.2.0
|
|
51
|
-
"@tmagic/schema": "1.2.0
|
|
52
|
-
"@tmagic/stage": "1.2.0
|
|
53
|
-
"@tmagic/utils": "1.2.0
|
|
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
|
|
66
|
-
"@tmagic/form": "1.2.0
|
|
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-
|
|
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
|
-
<
|
|
2
|
+
<Framework :code-options="codeOptions">
|
|
3
3
|
<template #nav>
|
|
4
|
-
<slot name="nav" :editorService="editorService"><
|
|
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
|
-
<
|
|
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';
|
|
@@ -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<
|
|
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,24 +216,40 @@ export default defineComponent({
|
|
|
207
216
|
},
|
|
208
217
|
|
|
209
218
|
updateDragEl: {
|
|
210
|
-
type: Function as PropType<
|
|
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
|
-
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
if (nodeId
|
|
221
|
-
editorService.
|
|
222
|
-
}
|
|
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
|
-
|
|
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.
|
|
301
|
-
historyService.
|
|
302
|
-
propsService.
|
|
303
|
-
uiService.
|
|
304
|
-
componentListService.
|
|
305
|
-
|
|
306
|
-
|
|
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('
|
|
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>
|
|
@@ -1,5 +1,5 @@
|
|
|
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"
|
|
@@ -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
|
@@ -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
|
|