@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.
- package/dist/style.css +59 -35
- package/dist/{tmagic-editor.mjs → tmagic-editor.js} +1473 -1154
- package/dist/tmagic-editor.js.map +1 -0
- package/dist/{tmagic-editor.umd.js → tmagic-editor.umd.cjs} +1483 -1159
- 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 +1 -1
- 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 +89 -102
- 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
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<TMagicDialog
|
|
3
|
-
|
|
3
|
+
:model-value="true"
|
|
4
4
|
class="code-editor-dialog"
|
|
5
5
|
:title="currentTitle"
|
|
6
6
|
:fullscreen="true"
|
|
7
|
-
:
|
|
7
|
+
:close-on-press-escape="false"
|
|
8
8
|
:append-to-body="true"
|
|
9
|
+
:show-close="false"
|
|
9
10
|
>
|
|
10
|
-
<
|
|
11
|
+
<Layout v-model:left="left" :min-left="45" class="code-editor-layout">
|
|
11
12
|
<!-- 左侧列表 -->
|
|
12
13
|
<template #left v-if="mode === CodeEditorMode.LIST">
|
|
13
14
|
<TMagicTree
|
|
@@ -40,62 +41,37 @@
|
|
|
40
41
|
]"
|
|
41
42
|
>
|
|
42
43
|
<slot name="code-block-edit-panel-header" :id="id"></slot>
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
/>
|
|
53
|
-
</div>
|
|
54
|
-
</template>
|
|
55
|
-
<div class="m-editor-wrapper">
|
|
56
|
-
<magic-code-editor
|
|
57
|
-
v-if="codeConfig"
|
|
58
|
-
ref="codeEditor"
|
|
59
|
-
class="m-editor-container"
|
|
60
|
-
:init-values="`${codeConfig.content}`"
|
|
61
|
-
@save="saveCode"
|
|
62
|
-
:options="{
|
|
63
|
-
tabSize: 2,
|
|
64
|
-
fontSize: 16,
|
|
65
|
-
formatOnPaste: true,
|
|
66
|
-
readOnly: !editable,
|
|
67
|
-
}"
|
|
68
|
-
></magic-code-editor>
|
|
69
|
-
<div class="m-editor-content-bottom" v-if="editable">
|
|
70
|
-
<TMagicButton type="primary" class="button" @click="saveCode">保存</TMagicButton>
|
|
71
|
-
<TMagicButton type="primary" class="button" @click="saveAndClose">关闭</TMagicButton>
|
|
72
|
-
</div>
|
|
73
|
-
<div class="m-editor-content-bottom" v-else>
|
|
74
|
-
<TMagicButton type="primary" class="button" @click="saveAndClose">关闭</TMagicButton>
|
|
75
|
-
</div>
|
|
76
|
-
</div>
|
|
77
|
-
</TMagicCard>
|
|
44
|
+
<FunctionEditor
|
|
45
|
+
v-if="codeConfig"
|
|
46
|
+
:id="id"
|
|
47
|
+
:name="codeConfig.name"
|
|
48
|
+
:content="codeConfig.content"
|
|
49
|
+
:editable="!!editable"
|
|
50
|
+
:autoSaveDraft="mode === CodeEditorMode.EDITOR"
|
|
51
|
+
:codeOptions="codeOptions"
|
|
52
|
+
></FunctionEditor>
|
|
78
53
|
</div>
|
|
79
54
|
</template>
|
|
80
|
-
</
|
|
55
|
+
</Layout>
|
|
81
56
|
</TMagicDialog>
|
|
82
57
|
</template>
|
|
83
58
|
|
|
84
|
-
<script lang="ts" setup>
|
|
59
|
+
<script lang="ts" setup name="MEditorCodeBlockEditor">
|
|
85
60
|
import { computed, inject, reactive, ref, watchEffect } from 'vue';
|
|
86
|
-
import { forIn, isEmpty } from 'lodash-es';
|
|
87
|
-
import type * as monaco from 'monaco-editor';
|
|
61
|
+
import { cloneDeep, forIn, isEmpty } from 'lodash-es';
|
|
88
62
|
|
|
89
|
-
import {
|
|
63
|
+
import { TMagicDialog, TMagicTree } from '@tmagic/design';
|
|
64
|
+
import { CodeBlockContent } from '@tmagic/schema';
|
|
90
65
|
|
|
91
|
-
import
|
|
66
|
+
import FunctionEditor from '../../../components/FunctionEditor.vue';
|
|
67
|
+
import Layout from '../../../components/Layout.vue';
|
|
68
|
+
import type { CodeDslItem, ListState, Services } from '../../../type';
|
|
92
69
|
import { CodeEditorMode } from '../../../type';
|
|
93
|
-
import
|
|
94
|
-
import Layout from '../../Layout.vue';
|
|
70
|
+
import { serializeConfig } from '../../../utils/editor';
|
|
95
71
|
|
|
96
72
|
const services = inject<Services>('services');
|
|
73
|
+
const codeOptions = inject('codeOptions', {});
|
|
97
74
|
|
|
98
|
-
const codeEditor = ref<InstanceType<typeof MagicCodeEditor>>();
|
|
99
75
|
const left = ref(200);
|
|
100
76
|
const currentTitle = ref('');
|
|
101
77
|
// 编辑器当前需展示的代码块内容
|
|
@@ -105,10 +81,6 @@ const state = reactive<ListState>({
|
|
|
105
81
|
codeList: [],
|
|
106
82
|
});
|
|
107
83
|
|
|
108
|
-
// 是否展示代码编辑区
|
|
109
|
-
const isShowCodeBlockEditor = computed(
|
|
110
|
-
() => (codeConfig.value && services?.codeBlockService.getCodeEditorShowStatus()) || false,
|
|
111
|
-
);
|
|
112
84
|
const mode = computed(() => services?.codeBlockService.getMode());
|
|
113
85
|
const id = computed(() => services?.codeBlockService.getId() || '');
|
|
114
86
|
const editable = computed(() => services?.codeBlockService.getEditStatus());
|
|
@@ -116,7 +88,9 @@ const editable = computed(() => services?.codeBlockService.getEditStatus());
|
|
|
116
88
|
const selectedIds = computed(() => services?.codeBlockService.getCombineIds() || []);
|
|
117
89
|
|
|
118
90
|
watchEffect(async () => {
|
|
119
|
-
codeConfig.value = (await services?.codeBlockService.getCodeContentById(id.value)) || null;
|
|
91
|
+
codeConfig.value = cloneDeep(await services?.codeBlockService.getCodeContentById(id.value)) || null;
|
|
92
|
+
if (!codeConfig.value) return;
|
|
93
|
+
codeConfig.value.content = serializeConfig(codeConfig.value.content);
|
|
120
94
|
});
|
|
121
95
|
|
|
122
96
|
watchEffect(async () => {
|
|
@@ -132,37 +106,7 @@ watchEffect(async () => {
|
|
|
132
106
|
currentTitle.value = state.codeList[0]?.name || '';
|
|
133
107
|
});
|
|
134
108
|
|
|
135
|
-
|
|
136
|
-
const saveCode = async (): Promise<boolean> => {
|
|
137
|
-
if (!codeEditor.value || !codeConfig.value || !editable.value) return true;
|
|
138
|
-
|
|
139
|
-
try {
|
|
140
|
-
// 代码内容
|
|
141
|
-
const codeContent = (codeEditor.value.getEditor() as monaco.editor.IStandaloneCodeEditor)?.getValue();
|
|
142
|
-
/* eslint no-eval: "off" */
|
|
143
|
-
codeConfig.value.content = eval(codeContent);
|
|
144
|
-
} catch (e: any) {
|
|
145
|
-
tMagicMessage.error(e.stack);
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
// 存入dsl
|
|
149
|
-
await services?.codeBlockService.setCodeDslById(id.value, {
|
|
150
|
-
name: codeConfig.value.name,
|
|
151
|
-
content: codeConfig.value.content,
|
|
152
|
-
});
|
|
153
|
-
tMagicMessage.success('代码保存成功');
|
|
154
|
-
return true;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
// 保存并关闭
|
|
158
|
-
const saveAndClose = async () => {
|
|
159
|
-
const saveRes = await saveCode();
|
|
160
|
-
if (saveRes) {
|
|
161
|
-
await services?.codeBlockService.setCodeEditorShowStatus(false);
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
const selectHandler = (data: CodeDslList) => {
|
|
109
|
+
const selectHandler = (data: CodeDslItem) => {
|
|
166
110
|
services?.codeBlockService.setId(data.id);
|
|
167
111
|
currentTitle.value = data.name;
|
|
168
112
|
};
|
|
@@ -17,75 +17,68 @@
|
|
|
17
17
|
</slot>
|
|
18
18
|
|
|
19
19
|
<!-- 代码块列表 -->
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<
|
|
32
|
-
<div class="list-
|
|
33
|
-
<div class="
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
20
|
+
<TMagicScrollbar>
|
|
21
|
+
<TMagicTree
|
|
22
|
+
v-if="!isEmpty(state.codeList)"
|
|
23
|
+
ref="tree"
|
|
24
|
+
node-key="id"
|
|
25
|
+
empty-text="暂无代码块"
|
|
26
|
+
:data="state.codeList"
|
|
27
|
+
:highlight-current="true"
|
|
28
|
+
:filter-node-method="filterNode"
|
|
29
|
+
@node-click="toggleCombineRelation"
|
|
30
|
+
>
|
|
31
|
+
<template #default="{ data }">
|
|
32
|
+
<div :id="data.id" class="list-container">
|
|
33
|
+
<div class="list-item">
|
|
34
|
+
<span class="code-name">{{ data.name }}({{ data.id }})</span>
|
|
35
|
+
<!-- 右侧工具栏 -->
|
|
36
|
+
<div class="right-tool">
|
|
37
|
+
<TMagicTooltip effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
|
|
38
|
+
<Icon :icon="editable ? Edit : View" class="edit-icon" @click.stop="editCode(`${data.id}`)"></Icon>
|
|
39
|
+
</TMagicTooltip>
|
|
40
|
+
<TMagicTooltip
|
|
41
|
+
effect="dark"
|
|
42
|
+
content="查看绑定关系"
|
|
43
|
+
placement="bottom"
|
|
44
|
+
v-if="data.combineInfo && data.combineInfo.length > 0"
|
|
45
|
+
>
|
|
46
|
+
<Icon :icon="Link" class="edit-icon" @click.stop="toggleCombineRelation(data)"></Icon>
|
|
47
|
+
</TMagicTooltip>
|
|
48
|
+
<TMagicTooltip effect="dark" content="删除" placement="bottom" v-if="editable">
|
|
49
|
+
<Icon :icon="Close" class="edit-icon" @click.stop="deleteCode(`${data.id}`)"></Icon>
|
|
50
|
+
</TMagicTooltip>
|
|
51
|
+
<slot name="code-block-panel-tool" :id="data.id" :data="data.codeBlockContent"></slot>
|
|
52
|
+
</div>
|
|
51
53
|
</div>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
v-if="data.showRelation && state.bindComps[data.id] && state.bindComps[data.id].length > 0"
|
|
57
|
-
>
|
|
58
|
-
<svg class="arrow-left" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-029747aa="">
|
|
59
|
-
<path
|
|
60
|
-
fill="currentColor"
|
|
61
|
-
d="M609.408 149.376 277.76 489.6a32 32 0 0 0 0 44.672l331.648 340.352a29.12 29.12 0 0 0 41.728 0 30.592 30.592 0 0 0 0-42.752L339.264 511.936l311.872-319.872a30.592 30.592 0 0 0 0-42.688 29.12 29.12 0 0 0-41.728 0z"
|
|
62
|
-
></path>
|
|
63
|
-
</svg>
|
|
64
|
-
<!-- todo 功能暂时隐藏 -->
|
|
65
|
-
<!-- <TMagicButton
|
|
66
|
-
v-for="(comp, index) in state.bindComps[data.id]"
|
|
67
|
-
:key="index"
|
|
68
|
-
class="code-comp"
|
|
69
|
-
size="small"
|
|
70
|
-
:plain="true"
|
|
71
|
-
>{{ comp.name }}<Icon :icon="Close" class="comp-delete-icon" @click.stop="unbind(comp.id, data.id)"></Icon
|
|
72
|
-
></TMagicButton> -->
|
|
73
|
-
<TMagicButton
|
|
74
|
-
v-for="(comp, index) in state.bindComps[data.id]"
|
|
75
|
-
:key="index"
|
|
76
|
-
class="code-comp"
|
|
77
|
-
size="small"
|
|
78
|
-
:plain="true"
|
|
79
|
-
@click.stop="selectComp(comp.id)"
|
|
80
|
-
>{{ comp.name }}</TMagicButton
|
|
54
|
+
<!-- 展示代码块下绑定的组件 -->
|
|
55
|
+
<div
|
|
56
|
+
class="code-comp-map-wrapper"
|
|
57
|
+
v-if="data.showRelation && data.combineInfo && data.combineInfo.length > 0"
|
|
81
58
|
>
|
|
59
|
+
<svg class="arrow-left" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-029747aa="">
|
|
60
|
+
<path
|
|
61
|
+
fill="currentColor"
|
|
62
|
+
d="M609.408 149.376 277.76 489.6a32 32 0 0 0 0 44.672l331.648 340.352a29.12 29.12 0 0 0 41.728 0 30.592 30.592 0 0 0 0-42.752L339.264 511.936l311.872-319.872a30.592 30.592 0 0 0 0-42.688 29.12 29.12 0 0 0-41.728 0z"
|
|
63
|
+
></path>
|
|
64
|
+
</svg>
|
|
65
|
+
<TMagicButton
|
|
66
|
+
v-for="(comp, index) in data.combineInfo"
|
|
67
|
+
:key="index"
|
|
68
|
+
class="code-comp"
|
|
69
|
+
size="small"
|
|
70
|
+
:plain="true"
|
|
71
|
+
@click.stop="selectComp(comp.compId)"
|
|
72
|
+
>{{ comp.compName }}</TMagicButton
|
|
73
|
+
>
|
|
74
|
+
</div>
|
|
82
75
|
</div>
|
|
83
|
-
</
|
|
84
|
-
</
|
|
85
|
-
</
|
|
76
|
+
</template>
|
|
77
|
+
</TMagicTree>
|
|
78
|
+
</TMagicScrollbar>
|
|
86
79
|
|
|
87
80
|
<!-- 代码块编辑区 -->
|
|
88
|
-
<code-block-editor>
|
|
81
|
+
<code-block-editor v-if="isShowCodeBlockEditor">
|
|
89
82
|
<template #code-block-edit-panel-header="{ id }">
|
|
90
83
|
<slot name="code-block-edit-panel-header" :id="id"></slot>
|
|
91
84
|
</template>
|
|
@@ -93,69 +86,68 @@
|
|
|
93
86
|
</div>
|
|
94
87
|
</template>
|
|
95
88
|
|
|
96
|
-
<script lang="ts" setup>
|
|
89
|
+
<script lang="ts" setup name="MEditorCodeBlockList">
|
|
97
90
|
import { computed, inject, reactive, ref, watch } from 'vue';
|
|
98
91
|
import { Close, Edit, Link, View } from '@element-plus/icons-vue';
|
|
99
|
-
import { forIn, isEmpty } from 'lodash-es';
|
|
92
|
+
import { cloneDeep, forIn, isEmpty } from 'lodash-es';
|
|
100
93
|
|
|
101
|
-
import { TMagicButton, TMagicInput, tMagicMessage, TMagicTooltip, TMagicTree } from '@tmagic/design';
|
|
102
|
-
import { Id } from '@tmagic/schema';
|
|
94
|
+
import { TMagicButton, TMagicInput, tMagicMessage, TMagicScrollbar, TMagicTooltip, TMagicTree } from '@tmagic/design';
|
|
95
|
+
import { CodeBlockContent, Id } from '@tmagic/schema';
|
|
103
96
|
import StageCore from '@tmagic/stage';
|
|
104
97
|
|
|
105
98
|
import Icon from '../../../components/Icon.vue';
|
|
106
|
-
import type {
|
|
107
|
-
import { CodeDeleteErrorType,
|
|
99
|
+
import type { CodeRelation, Services } from '../../../type';
|
|
100
|
+
import { CodeDeleteErrorType, CodeDslItem, CodeEditorMode, ListState } from '../../../type';
|
|
108
101
|
|
|
109
102
|
import codeBlockEditor from './CodeBlockEditor.vue';
|
|
110
103
|
|
|
111
104
|
const props = defineProps<{
|
|
112
|
-
customError?: (id:
|
|
105
|
+
customError?: (id: Id, errorType: CodeDeleteErrorType) => any;
|
|
113
106
|
}>();
|
|
114
107
|
|
|
115
108
|
const services = inject<Services>('services');
|
|
116
109
|
|
|
117
110
|
// 代码块列表
|
|
118
|
-
const state = reactive<
|
|
111
|
+
const state = reactive<ListState>({
|
|
119
112
|
codeList: [],
|
|
120
|
-
bindComps: {},
|
|
121
113
|
});
|
|
122
114
|
|
|
123
115
|
const editable = computed(() => services?.codeBlockService.getEditStatus());
|
|
124
116
|
|
|
117
|
+
// 是否展示代码编辑区
|
|
118
|
+
const isShowCodeBlockEditor = computed(() => services?.codeBlockService.getCodeEditorShowStatus() || false);
|
|
119
|
+
// 获取绑定关系
|
|
120
|
+
const codeCombineInfo = ref<CodeRelation | null>(null);
|
|
121
|
+
|
|
125
122
|
// 根据代码块ID获取其绑定的组件信息
|
|
126
|
-
const getBindCompsByCodeId = (codeId:
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const bindCompIds = Object.keys(compsField);
|
|
133
|
-
const bindCompsFiltered = bindCompIds.filter((compId) => !isEmpty(compsField[compId]));
|
|
134
|
-
const compsInfo = bindCompsFiltered.map((compId) => ({
|
|
135
|
-
id: compId,
|
|
136
|
-
name: getCompName(compId),
|
|
123
|
+
const getBindCompsByCodeId = (codeId: Id) => {
|
|
124
|
+
if (!codeCombineInfo.value || !codeCombineInfo.value[codeId]) return [];
|
|
125
|
+
const bindCompsId = Object.keys(codeCombineInfo.value[codeId]);
|
|
126
|
+
return bindCompsId.map((compId) => ({
|
|
127
|
+
compId,
|
|
128
|
+
compName: getCompName(compId),
|
|
137
129
|
}));
|
|
138
|
-
state.bindComps[codeId] = compsInfo;
|
|
139
130
|
};
|
|
140
131
|
|
|
141
132
|
// 初始化代码块列表
|
|
142
133
|
const initList = async () => {
|
|
143
|
-
const codeDsl = (await services?.codeBlockService.getCodeDsl()) || null;
|
|
144
|
-
|
|
134
|
+
const codeDsl = cloneDeep(await services?.codeBlockService.getCodeDsl()) || null;
|
|
135
|
+
codeCombineInfo.value = cloneDeep(services?.codeBlockService.getCombineInfo()) || null;
|
|
136
|
+
if (!codeDsl || !codeCombineInfo.value) return;
|
|
145
137
|
state.codeList = [];
|
|
146
|
-
forIn(codeDsl, (value: CodeBlockContent, codeId:
|
|
147
|
-
getBindCompsByCodeId(codeId, value);
|
|
138
|
+
forIn(codeDsl, (value: CodeBlockContent, codeId: Id) => {
|
|
148
139
|
state.codeList.push({
|
|
149
140
|
id: codeId,
|
|
150
141
|
name: value.name,
|
|
151
142
|
codeBlockContent: value,
|
|
152
143
|
showRelation: true,
|
|
144
|
+
combineInfo: getBindCompsByCodeId(codeId),
|
|
153
145
|
});
|
|
154
146
|
});
|
|
155
147
|
};
|
|
156
148
|
|
|
157
149
|
watch(
|
|
158
|
-
() => services?.codeBlockService.
|
|
150
|
+
[() => services?.codeBlockService.getCodeDslSync(), () => services?.codeBlockService.refreshCombineInfo()],
|
|
159
151
|
() => {
|
|
160
152
|
initList();
|
|
161
153
|
},
|
|
@@ -165,21 +157,6 @@ watch(
|
|
|
165
157
|
},
|
|
166
158
|
);
|
|
167
159
|
|
|
168
|
-
// 监听组件名称修改,更新到代码块列表
|
|
169
|
-
watch(
|
|
170
|
-
() => services?.editorService.get('node'),
|
|
171
|
-
(curNode) => {
|
|
172
|
-
if (!curNode?.id) return;
|
|
173
|
-
forIn(state.bindComps, (bindCompInfo) => {
|
|
174
|
-
bindCompInfo.forEach((comp) => {
|
|
175
|
-
if (comp.id === curNode.id) {
|
|
176
|
-
comp.name = curNode.name;
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
},
|
|
181
|
-
);
|
|
182
|
-
|
|
183
160
|
// 新增代码块
|
|
184
161
|
const createCodeBlock = async () => {
|
|
185
162
|
const { codeBlockService } = services || {};
|
|
@@ -189,7 +166,8 @@ const createCodeBlock = async () => {
|
|
|
189
166
|
}
|
|
190
167
|
const codeConfig: CodeBlockContent = {
|
|
191
168
|
name: '代码块',
|
|
192
|
-
content: `() => {\n // place your code here\n}`,
|
|
169
|
+
content: `({app, params}) => {\n // place your code here\n}`,
|
|
170
|
+
params: [],
|
|
193
171
|
};
|
|
194
172
|
await codeBlockService.setMode(CodeEditorMode.EDITOR);
|
|
195
173
|
const id = await codeBlockService.getUniqueId();
|
|
@@ -198,14 +176,15 @@ const createCodeBlock = async () => {
|
|
|
198
176
|
};
|
|
199
177
|
|
|
200
178
|
// 编辑代码块
|
|
201
|
-
const editCode = async (key:
|
|
179
|
+
const editCode = async (key: Id) => {
|
|
202
180
|
await services?.codeBlockService.setMode(CodeEditorMode.EDITOR);
|
|
203
181
|
services?.codeBlockService.setCodeEditorContent(true, key);
|
|
204
182
|
};
|
|
205
183
|
|
|
206
184
|
// 删除代码块
|
|
207
|
-
const deleteCode = (key:
|
|
208
|
-
const
|
|
185
|
+
const deleteCode = (key: Id) => {
|
|
186
|
+
const currentCode = state.codeList.find((codeItem: CodeDslItem) => codeItem.id === key);
|
|
187
|
+
const existBinds = !isEmpty(currentCode?.combineInfo);
|
|
209
188
|
const undeleteableList = services?.codeBlockService.getUndeletableList() || [];
|
|
210
189
|
if (!existBinds && !undeleteableList.includes(key)) {
|
|
211
190
|
// 无绑定关系,且不在不可删除列表中
|
|
@@ -222,7 +201,7 @@ const deleteCode = (key: string) => {
|
|
|
222
201
|
const filterText = ref('');
|
|
223
202
|
const tree = ref();
|
|
224
203
|
|
|
225
|
-
const filterNode = (value: string, data:
|
|
204
|
+
const filterNode = (value: string, data: CodeDslItem): boolean => {
|
|
226
205
|
if (!value) {
|
|
227
206
|
return true;
|
|
228
207
|
}
|
|
@@ -234,7 +213,7 @@ const filterTextChangeHandler = (val: string) => {
|
|
|
234
213
|
};
|
|
235
214
|
|
|
236
215
|
// 展示/隐藏组件绑定关系
|
|
237
|
-
const toggleCombineRelation = (data:
|
|
216
|
+
const toggleCombineRelation = (data: CodeDslItem) => {
|
|
238
217
|
const { id } = data;
|
|
239
218
|
const currentCode = state.codeList.find((item) => item.id === id);
|
|
240
219
|
if (!currentCode) return;
|
|
@@ -247,17 +226,6 @@ const getCompName = (compId: Id): string => {
|
|
|
247
226
|
return node?.name || String(compId);
|
|
248
227
|
};
|
|
249
228
|
|
|
250
|
-
// todo 功能暂时隐藏
|
|
251
|
-
// 解除绑定
|
|
252
|
-
// const unbind = async (compId: Id, codeId: string) => {
|
|
253
|
-
// const res = await services?.codeBlockService.unbind(compId, codeId, codeHooks);
|
|
254
|
-
// if (res) {
|
|
255
|
-
// ElMessage.success('绑定关系解除成功');
|
|
256
|
-
// } else {
|
|
257
|
-
// ElMessage.error('绑定关系解除失败');
|
|
258
|
-
// }
|
|
259
|
-
// };
|
|
260
|
-
|
|
261
229
|
// 选中组件
|
|
262
230
|
const selectComp = (compId: Id) => {
|
|
263
231
|
const stage = services?.editorService.get<StageCore | null>('stage');
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
</div>
|
|
27
27
|
</template>
|
|
28
28
|
|
|
29
|
-
<script setup lang="ts">
|
|
29
|
+
<script setup lang="ts" name="MEditorPageBarScrollContainer">
|
|
30
30
|
import { computed, inject, nextTick, onMounted, onUnmounted, ref, toRaw, watch } from 'vue';
|
|
31
31
|
import { ArrowLeftBold, ArrowRightBold, Plus } from '@element-plus/icons-vue';
|
|
32
32
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<ScrollViewer
|
|
3
3
|
class="m-editor-stage"
|
|
4
4
|
ref="stageWrap"
|
|
5
5
|
:width="stageRect?.width"
|
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
:wrap-width="stageContainerRect?.width"
|
|
8
8
|
:wrap-height="stageContainerRect?.height"
|
|
9
9
|
:zoom="zoom"
|
|
10
|
+
:correction-scroll-size="{
|
|
11
|
+
width: 60,
|
|
12
|
+
height: 50,
|
|
13
|
+
}"
|
|
10
14
|
>
|
|
11
15
|
<div
|
|
12
16
|
class="m-editor-stage-container"
|
|
@@ -16,25 +20,29 @@
|
|
|
16
20
|
@drop="dropHandler"
|
|
17
21
|
@dragover="dragoverHandler"
|
|
18
22
|
></div>
|
|
19
|
-
<
|
|
20
|
-
<
|
|
21
|
-
</
|
|
22
|
-
</
|
|
23
|
+
<Teleport to="body">
|
|
24
|
+
<ViewerMenu ref="menu" :is-multi-select="isMultiSelect" :stage-content-menu="stageContentMenu"></ViewerMenu>
|
|
25
|
+
</Teleport>
|
|
26
|
+
</ScrollViewer>
|
|
23
27
|
</template>
|
|
24
28
|
|
|
25
|
-
<script lang="ts" setup>
|
|
26
|
-
import { computed, inject, markRaw, onMounted, onUnmounted, ref, toRaw, watch, watchEffect } from 'vue';
|
|
29
|
+
<script lang="ts" setup name="MEditorStage">
|
|
30
|
+
import { computed, inject, markRaw, nextTick, onMounted, onUnmounted, ref, toRaw, watch, watchEffect } from 'vue';
|
|
27
31
|
import { cloneDeep } from 'lodash-es';
|
|
28
32
|
|
|
29
33
|
import type { MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
30
34
|
import StageCore, { calcValueByFontsize, getOffset, Runtime } from '@tmagic/stage';
|
|
31
35
|
|
|
32
36
|
import ScrollViewer from '../../components/ScrollViewer.vue';
|
|
33
|
-
import { Layout, Services, StageOptions, StageRect } from '../../type';
|
|
37
|
+
import { Layout, MenuButton, MenuComponent, Services, StageOptions, StageRect } from '../../type';
|
|
34
38
|
import { useStage } from '../../utils/stage';
|
|
35
39
|
|
|
36
40
|
import ViewerMenu from './ViewerMenu.vue';
|
|
37
41
|
|
|
42
|
+
defineProps<{
|
|
43
|
+
stageContentMenu: (MenuButton | MenuComponent)[];
|
|
44
|
+
}>();
|
|
45
|
+
|
|
38
46
|
let stage: StageCore | null = null;
|
|
39
47
|
let runtime: Runtime | null = null;
|
|
40
48
|
|
|
@@ -54,7 +62,7 @@ const zoom = computed(() => services?.uiService.get<number>('zoom') || 1);
|
|
|
54
62
|
const node = computed(() => services?.editorService.get<MNode>('node'));
|
|
55
63
|
|
|
56
64
|
watchEffect(() => {
|
|
57
|
-
if (stage) return;
|
|
65
|
+
if (stage || !page.value) return;
|
|
58
66
|
|
|
59
67
|
if (!stageContainer.value) return;
|
|
60
68
|
if (!(stageOptions?.runtimeUrl || stageOptions?.render) || !root.value) return;
|
|
@@ -88,6 +96,15 @@ watch(root, (root) => {
|
|
|
88
96
|
}
|
|
89
97
|
});
|
|
90
98
|
|
|
99
|
+
watch(page, (page) => {
|
|
100
|
+
if (runtime && page) {
|
|
101
|
+
runtime.updatePageId?.(page.id);
|
|
102
|
+
nextTick(() => {
|
|
103
|
+
stage?.select(page.id);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
91
108
|
const resizeObserver = new ResizeObserver((entries) => {
|
|
92
109
|
for (const { contentRect } of entries) {
|
|
93
110
|
services?.uiService.set('stageContainerRect', {
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
<content-menu :menu-data="menuData" ref="menu"></content-menu>
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
|
-
<script lang="ts" setup>
|
|
6
|
-
import { computed, inject, markRaw,
|
|
7
|
-
import { Bottom, Delete, DocumentCopy, Top } from '@element-plus/icons-vue';
|
|
5
|
+
<script lang="ts" setup name="MEditorViewerMenu">
|
|
6
|
+
import { computed, inject, markRaw, ref, watch } from 'vue';
|
|
7
|
+
import { Bottom, CopyDocument, Delete, DocumentCopy, Top } from '@element-plus/icons-vue';
|
|
8
8
|
|
|
9
9
|
import { MNode, NodeType } from '@tmagic/schema';
|
|
10
10
|
import StageCore from '@tmagic/stage';
|
|
@@ -15,7 +15,10 @@ import storageService from '../../services/storage';
|
|
|
15
15
|
import { LayerOffset, Layout, MenuButton, MenuComponent, Services } from '../../type';
|
|
16
16
|
import { COPY_STORAGE_KEY } from '../../utils/editor';
|
|
17
17
|
|
|
18
|
-
const props = withDefaults(
|
|
18
|
+
const props = withDefaults(
|
|
19
|
+
defineProps<{ isMultiSelect?: boolean; stageContentMenu: (MenuButton | MenuComponent)[] }>(),
|
|
20
|
+
{ isMultiSelect: false },
|
|
21
|
+
);
|
|
19
22
|
|
|
20
23
|
const services = inject<Services>('services');
|
|
21
24
|
const editorService = services?.editorService;
|
|
@@ -28,9 +31,7 @@ const nodes = computed(() => editorService?.get<MNode[]>('nodes'));
|
|
|
28
31
|
const parent = computed(() => editorService?.get('parent'));
|
|
29
32
|
const stage = computed(() => editorService?.get<StageCore>('stage'));
|
|
30
33
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
const menuData = reactive<(MenuButton | MenuComponent)[]>([
|
|
34
|
+
const menuData = computed<(MenuButton | MenuComponent)[]>(() => [
|
|
34
35
|
{
|
|
35
36
|
type: 'button',
|
|
36
37
|
text: '水平居中',
|
|
@@ -43,7 +44,7 @@ const menuData = reactive<(MenuButton | MenuComponent)[]>([
|
|
|
43
44
|
{
|
|
44
45
|
type: 'button',
|
|
45
46
|
text: '复制',
|
|
46
|
-
icon: markRaw(
|
|
47
|
+
icon: markRaw(CopyDocument),
|
|
47
48
|
handler: () => {
|
|
48
49
|
nodes.value && editorService?.copy(nodes.value);
|
|
49
50
|
canPaste.value = true;
|
|
@@ -52,6 +53,7 @@ const menuData = reactive<(MenuButton | MenuComponent)[]>([
|
|
|
52
53
|
{
|
|
53
54
|
type: 'button',
|
|
54
55
|
text: '粘贴',
|
|
56
|
+
icon: markRaw(DocumentCopy),
|
|
55
57
|
display: () => canPaste.value,
|
|
56
58
|
handler: () => {
|
|
57
59
|
const rect = menu.value?.$el.getBoundingClientRect();
|
|
@@ -130,7 +132,7 @@ const menuData = reactive<(MenuButton | MenuComponent)[]>([
|
|
|
130
132
|
editorService?.get<StageCore>('stage').clearGuides();
|
|
131
133
|
},
|
|
132
134
|
},
|
|
133
|
-
...stageContentMenu,
|
|
135
|
+
...props.stageContentMenu,
|
|
134
136
|
]);
|
|
135
137
|
|
|
136
138
|
watch(
|