@tmagic/editor 1.1.6 → 1.2.0-beta.1
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 +177 -0
- package/dist/tmagic-editor.mjs +1104 -158
- package/dist/tmagic-editor.mjs.map +1 -1
- package/dist/tmagic-editor.umd.js +1111 -160
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/package.json +7 -7
- package/src/Editor.vue +18 -1
- package/src/fields/CodeSelect.vue +139 -0
- package/src/index.ts +4 -1
- package/src/layouts/Layout.vue +1 -1
- package/src/layouts/PropsPanel.vue +1 -1
- package/src/layouts/sidebar/Sidebar.vue +13 -1
- package/src/layouts/sidebar/TabPane.vue +28 -1
- package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +165 -0
- package/src/layouts/sidebar/code-block/CodeBlockList.vue +267 -0
- package/src/services/codeBlock.ts +409 -0
- package/src/services/editor.ts +27 -1
- package/src/theme/code-block.scss +184 -0
- package/src/theme/index.scss +2 -0
- package/src/theme/layout.scss +5 -0
- package/src/type.ts +87 -1
- package/src/utils/props.ts +9 -3
- package/types/fields/CodeSelect.vue.d.ts +96 -0
- package/types/index.d.ts +2 -0
- package/types/layouts/sidebar/LayerPanel.vue.d.ts +3 -3
- package/types/layouts/sidebar/code-block/CodeBlockEditor.vue.d.ts +50 -0
- package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +72 -0
- package/types/services/codeBlock.d.ts +155 -0
- package/types/services/editor.d.ts +12 -1
- package/types/services/props.d.ts +12 -0
- package/types/type.d.ts +77 -1
- package/types/utils/props.d.ts +12 -0
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.1
|
|
2
|
+
"version": "1.2.0-beta.1",
|
|
3
3
|
"name": "@tmagic/editor",
|
|
4
4
|
"sideEffects": [
|
|
5
5
|
"dist/*",
|
|
@@ -45,11 +45,11 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@babel/core": "^7.18.0",
|
|
47
47
|
"@element-plus/icons-vue": "^2.0.9",
|
|
48
|
-
"@tmagic/core": "1.1
|
|
49
|
-
"@tmagic/form": "1.1
|
|
50
|
-
"@tmagic/schema": "1.1
|
|
51
|
-
"@tmagic/stage": "1.1
|
|
52
|
-
"@tmagic/utils": "1.1
|
|
48
|
+
"@tmagic/core": "1.2.0-beta.1",
|
|
49
|
+
"@tmagic/form": "1.2.0-beta.1",
|
|
50
|
+
"@tmagic/schema": "1.2.0-beta.1",
|
|
51
|
+
"@tmagic/stage": "1.2.0-beta.1",
|
|
52
|
+
"@tmagic/utils": "1.2.0-beta.1",
|
|
53
53
|
"buffer": "^6.0.3",
|
|
54
54
|
"color": "^3.1.3",
|
|
55
55
|
"element-plus": "^2.2.17",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"vue": "^3.2.37"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
|
-
"@tmagic/form": "1.1
|
|
65
|
+
"@tmagic/form": "1.2.0-beta.1",
|
|
66
66
|
"element-plus": "^2.2.17",
|
|
67
67
|
"monaco-editor": "^0.34.0",
|
|
68
68
|
"vue": "^3.2.37"
|
package/src/Editor.vue
CHANGED
|
@@ -22,6 +22,18 @@
|
|
|
22
22
|
<template #component-list-item="{ component }">
|
|
23
23
|
<slot name="component-list-item" :component="component"></slot>
|
|
24
24
|
</template>
|
|
25
|
+
|
|
26
|
+
<template #code-block-panel-header>
|
|
27
|
+
<slot name="code-block-panel-header"></slot>
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<template #code-block-panel-tool="{ id }">
|
|
31
|
+
<slot name="code-block-panel-tool" :id="id"></slot>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<template #code-block-edit-panel-header="{ id }">
|
|
35
|
+
<slot name="code-block-edit-panel-header" :id="id"></slot>
|
|
36
|
+
</template>
|
|
25
37
|
</sidebar>
|
|
26
38
|
</slot>
|
|
27
39
|
</template>
|
|
@@ -65,6 +77,7 @@ import NavMenu from './layouts/NavMenu.vue';
|
|
|
65
77
|
import PropsPanel from './layouts/PropsPanel.vue';
|
|
66
78
|
import Sidebar from './layouts/sidebar/Sidebar.vue';
|
|
67
79
|
import Workspace from './layouts/workspace/Workspace.vue';
|
|
80
|
+
import codeBlockService from './services/codeBlock';
|
|
68
81
|
import componentListService from './services/componentList';
|
|
69
82
|
import editorService from './services/editor';
|
|
70
83
|
import eventsService from './services/events';
|
|
@@ -216,7 +229,9 @@ export default defineComponent({
|
|
|
216
229
|
// 初始值变化,重新设置节点信息
|
|
217
230
|
watch(
|
|
218
231
|
() => props.modelValue,
|
|
219
|
-
(modelValue) =>
|
|
232
|
+
(modelValue) => {
|
|
233
|
+
editorService.set('root', modelValue);
|
|
234
|
+
},
|
|
220
235
|
{
|
|
221
236
|
immediate: true,
|
|
222
237
|
},
|
|
@@ -288,6 +303,7 @@ export default defineComponent({
|
|
|
288
303
|
uiService.destroy();
|
|
289
304
|
componentListService.destroy();
|
|
290
305
|
storageService.destroy();
|
|
306
|
+
codeBlockService.destroy();
|
|
291
307
|
});
|
|
292
308
|
|
|
293
309
|
const services: Services = {
|
|
@@ -298,6 +314,7 @@ export default defineComponent({
|
|
|
298
314
|
editorService,
|
|
299
315
|
uiService,
|
|
300
316
|
storageService,
|
|
317
|
+
codeBlockService,
|
|
301
318
|
};
|
|
302
319
|
|
|
303
320
|
provide('services', services);
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="m-fields-code-select" :key="fieldKey">
|
|
3
|
+
<el-card shadow="never">
|
|
4
|
+
<template #header>
|
|
5
|
+
<m-fields-select
|
|
6
|
+
:config="selectConfig"
|
|
7
|
+
:model="model"
|
|
8
|
+
:prop="prop"
|
|
9
|
+
:name="name"
|
|
10
|
+
:size="size"
|
|
11
|
+
@change="changeHandler"
|
|
12
|
+
></m-fields-select>
|
|
13
|
+
</template>
|
|
14
|
+
<div class="tool-bar">
|
|
15
|
+
<el-tooltip class="tool-item" effect="dark" content="查看代码块" placement="top">
|
|
16
|
+
<svg
|
|
17
|
+
@click="viewHandler"
|
|
18
|
+
preserveAspectRatio="xMidYMid meet"
|
|
19
|
+
viewBox="0 0 24 24"
|
|
20
|
+
width="15px"
|
|
21
|
+
height="15px"
|
|
22
|
+
data-v-65a7fb6c=""
|
|
23
|
+
>
|
|
24
|
+
<path
|
|
25
|
+
fill="currentColor"
|
|
26
|
+
d="m23 12l-7.071 7.071l-1.414-1.414L20.172 12l-5.657-5.657l1.414-1.414L23 12zM3.828 12l5.657 5.657l-1.414 1.414L1 12l7.071-7.071l1.414 1.414L3.828 12z"
|
|
27
|
+
></path>
|
|
28
|
+
</svg>
|
|
29
|
+
</el-tooltip>
|
|
30
|
+
</div>
|
|
31
|
+
</el-card>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script lang="ts" setup>
|
|
36
|
+
import { computed, defineEmits, defineProps, inject, ref, watchEffect } from 'vue';
|
|
37
|
+
import { ElMessage } from 'element-plus';
|
|
38
|
+
import { cloneDeep, map, xor } from 'lodash-es';
|
|
39
|
+
|
|
40
|
+
import { SelectConfig } from '@tmagic/form';
|
|
41
|
+
|
|
42
|
+
import type { Services } from '../type';
|
|
43
|
+
import { CodeEditorMode, CodeSelectOp } from '../type';
|
|
44
|
+
const services = inject<Services>('services');
|
|
45
|
+
|
|
46
|
+
const emit = defineEmits(['change']);
|
|
47
|
+
|
|
48
|
+
const props = defineProps<{
|
|
49
|
+
config: {
|
|
50
|
+
selectConfig?: SelectConfig;
|
|
51
|
+
};
|
|
52
|
+
model: any;
|
|
53
|
+
prop: string;
|
|
54
|
+
name: string;
|
|
55
|
+
size: string;
|
|
56
|
+
}>();
|
|
57
|
+
|
|
58
|
+
const selectConfig = computed(() => {
|
|
59
|
+
const defaultConfig = {
|
|
60
|
+
multiple: true,
|
|
61
|
+
options: async () => {
|
|
62
|
+
const codeDsl = await services?.codeBlockService.getCodeDsl();
|
|
63
|
+
if (codeDsl) {
|
|
64
|
+
return map(codeDsl, (value, key) => ({
|
|
65
|
+
text: `${value.name}(${key})`,
|
|
66
|
+
label: `${value.name}(${key})`,
|
|
67
|
+
value: key,
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
return [];
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
...defaultConfig,
|
|
75
|
+
...props.config.selectConfig,
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
const fieldKey = ref('');
|
|
79
|
+
const multiple = ref(true);
|
|
80
|
+
const combineIds = ref<string[]>([]);
|
|
81
|
+
let lastTagSnapshot = cloneDeep(props.model[props.name]) || [];
|
|
82
|
+
|
|
83
|
+
watchEffect(async () => {
|
|
84
|
+
const combineNames = await Promise.all(
|
|
85
|
+
combineIds.value.map(async (id) => {
|
|
86
|
+
const { name = '' } = (await services?.codeBlockService.getCodeContentById(id)) || {};
|
|
87
|
+
return name;
|
|
88
|
+
}),
|
|
89
|
+
);
|
|
90
|
+
fieldKey.value = combineNames.join('-');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const changeHandler = async (value: any) => {
|
|
94
|
+
let codeIds = value;
|
|
95
|
+
if (typeof value === 'string') {
|
|
96
|
+
multiple.value = false;
|
|
97
|
+
lastTagSnapshot = [lastTagSnapshot];
|
|
98
|
+
codeIds = value ? [value] : [];
|
|
99
|
+
}
|
|
100
|
+
await setCombineRelation(codeIds);
|
|
101
|
+
emit('change', value);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// 同步绑定关系
|
|
105
|
+
const setCombineRelation = async (codeIds: string[]) => {
|
|
106
|
+
// 组件id
|
|
107
|
+
const { id = '' } = services?.editorService.get('node') || {};
|
|
108
|
+
|
|
109
|
+
// 兼容单选
|
|
110
|
+
let opFlag = CodeSelectOp.CHANGE;
|
|
111
|
+
let diffValues = codeIds;
|
|
112
|
+
if (multiple.value) {
|
|
113
|
+
opFlag = codeIds.length < lastTagSnapshot.length ? CodeSelectOp.DELETE : CodeSelectOp.ADD;
|
|
114
|
+
diffValues = xor(codeIds, lastTagSnapshot) as string[];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 记录绑定关系
|
|
118
|
+
await services?.codeBlockService.setCombineRelation(id, diffValues, opFlag, props.prop);
|
|
119
|
+
lastTagSnapshot = codeIds;
|
|
120
|
+
await setCombineIds(codeIds);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// 记录当前已被绑定的代码块,为查看弹窗的展示内容
|
|
124
|
+
const setCombineIds = async (codeIds: string[]) => {
|
|
125
|
+
combineIds.value = codeIds;
|
|
126
|
+
await services?.codeBlockService.setCombineIds(codeIds);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const viewHandler = async () => {
|
|
130
|
+
if (props.model[props.name].length === 0) {
|
|
131
|
+
ElMessage.error('请先绑定代码块');
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
// 记录当前已被绑定的代码块,为查看弹窗的展示内容
|
|
135
|
+
await setCombineIds(props.model[props.name]);
|
|
136
|
+
await services?.codeBlockService.setMode(CodeEditorMode.LIST);
|
|
137
|
+
services?.codeBlockService.setCodeEditorContent(true, combineIds.value[0]);
|
|
138
|
+
};
|
|
139
|
+
</script>
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { App } from 'vue';
|
|
|
19
19
|
|
|
20
20
|
import Code from './fields/Code.vue';
|
|
21
21
|
import CodeLink from './fields/CodeLink.vue';
|
|
22
|
+
import CodeSelect from './fields/CodeSelect.vue';
|
|
22
23
|
import uiSelect from './fields/UISelect.vue';
|
|
23
24
|
import CodeEditor from './layouts/CodeEditor.vue';
|
|
24
25
|
import { setConfig } from './utils/config';
|
|
@@ -38,8 +39,10 @@ export { default as historyService } from './services/history';
|
|
|
38
39
|
export { default as storageService } from './services/storage';
|
|
39
40
|
export { default as eventsService } from './services/events';
|
|
40
41
|
export { default as uiService } from './services/ui';
|
|
42
|
+
export { default as codeBlockService } from './services/codeBlock';
|
|
41
43
|
export { default as ComponentListPanel } from './layouts/sidebar/ComponentListPanel.vue';
|
|
42
44
|
export { default as LayerPanel } from './layouts/sidebar/LayerPanel.vue';
|
|
45
|
+
export { default as CodeBlockList } from './layouts/sidebar/code-block/CodeBlockList.vue';
|
|
43
46
|
export { default as PropsPanel } from './layouts/PropsPanel.vue';
|
|
44
47
|
export { default as ToolButton } from './components/ToolButton.vue';
|
|
45
48
|
export { default as ContentMenu } from './components/ContentMenu.vue';
|
|
@@ -56,11 +59,11 @@ export default {
|
|
|
56
59
|
// eslint-disable-next-line no-param-reassign
|
|
57
60
|
app.config.globalProperties.$TMAGIC_EDITOR = option;
|
|
58
61
|
setConfig(option);
|
|
59
|
-
|
|
60
62
|
app.component(Editor.name, Editor);
|
|
61
63
|
app.component('m-fields-ui-select', uiSelect);
|
|
62
64
|
app.component('m-fields-code-link', CodeLink);
|
|
63
65
|
app.component('m-fields-vs-code', Code);
|
|
64
66
|
app.component(CodeEditor.name, CodeEditor);
|
|
67
|
+
app.component('m-fields-code-select', CodeSelect);
|
|
65
68
|
},
|
|
66
69
|
};
|
package/src/layouts/Layout.vue
CHANGED
|
@@ -22,6 +22,18 @@
|
|
|
22
22
|
<template #component-list-item="{ component }" v-if="item === 'component-list'">
|
|
23
23
|
<slot name="component-list-item" :component="component"></slot>
|
|
24
24
|
</template>
|
|
25
|
+
|
|
26
|
+
<template #code-block-panel-header v-if="item === 'code-block'">
|
|
27
|
+
<slot name="code-block-panel-header"></slot>
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<template #code-block-panel-tool="{ id }" v-if="item === 'code-block'">
|
|
31
|
+
<slot name="code-block-panel-tool" :id="id"></slot>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<template #code-block-edit-panel-header="{ id }" v-if="item === 'code-block'">
|
|
35
|
+
<slot name="code-block-edit-panel-header" :id="id"></slot>
|
|
36
|
+
</template>
|
|
25
37
|
</tab-pane>
|
|
26
38
|
</el-tabs>
|
|
27
39
|
</template>
|
|
@@ -41,7 +53,7 @@ export default defineComponent({
|
|
|
41
53
|
props: {
|
|
42
54
|
data: {
|
|
43
55
|
type: Object as PropType<SideBarData>,
|
|
44
|
-
default: () => ({ type: 'tabs', status: '组件', items: ['component-list', 'layer'] }),
|
|
56
|
+
default: () => ({ type: 'tabs', status: '组件', items: ['component-list', 'layer', 'code-block'] }),
|
|
45
57
|
},
|
|
46
58
|
},
|
|
47
59
|
|
|
@@ -30,6 +30,24 @@
|
|
|
30
30
|
<component v-else-if="config.slots?.layerPanelHeader" :is="config.slots.layerPanelHeader" />
|
|
31
31
|
</template>
|
|
32
32
|
|
|
33
|
+
<template #code-block-panel-header v-if="data === 'code-block' || config.slots?.codeBlockPanelHeader">
|
|
34
|
+
<slot v-if="data === 'code-block'" name="code-block-panel-header"></slot>
|
|
35
|
+
<component v-else-if="config.slots?.codeBlockPanelHeader" :is="config.slots.codeBlockPanelHeader" />
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<template #code-block-panel-tool="{ id }" v-if="data === 'code-block' || config.slots?.codeBlockPanelTool">
|
|
39
|
+
<slot v-if="data === 'code-block'" name="code-block-panel-tool" :id="id"></slot>
|
|
40
|
+
<component v-else-if="config.slots?.codeBlockPanelTool" :is="config.slots.codeBlockPanelTool" />
|
|
41
|
+
</template>
|
|
42
|
+
|
|
43
|
+
<template
|
|
44
|
+
#code-block-edit-panel-header="{ id }"
|
|
45
|
+
v-if="data === 'code-block' || config.slots?.codeBlockEditPanelHeader"
|
|
46
|
+
>
|
|
47
|
+
<slot v-if="data === 'code-block'" name="code-block-edit-panel-header" :id="id"></slot>
|
|
48
|
+
<component v-else-if="config.slots?.codeBlockEditPanelHeader" :is="config.slots.codeBlockEditPanelHeader" />
|
|
49
|
+
</template>
|
|
50
|
+
|
|
33
51
|
<template
|
|
34
52
|
#layer-node-content="{ data: nodeData, node }"
|
|
35
53
|
v-if="data === 'layer' || config.slots?.layerNodeContent"
|
|
@@ -48,11 +66,12 @@
|
|
|
48
66
|
|
|
49
67
|
<script lang="ts">
|
|
50
68
|
import { computed, defineComponent, PropType } from 'vue';
|
|
51
|
-
import { Coin, Files } from '@element-plus/icons-vue';
|
|
69
|
+
import { Coin, EditPen, Files } from '@element-plus/icons-vue';
|
|
52
70
|
|
|
53
71
|
import MIcon from '../../components/Icon.vue';
|
|
54
72
|
import { SideComponent, SideItem } from '../../type';
|
|
55
73
|
|
|
74
|
+
import CodeBlockList from './code-block/CodeBlockList.vue';
|
|
56
75
|
import ComponentListPanel from './ComponentListPanel.vue';
|
|
57
76
|
import LayerPanel from './LayerPanel.vue';
|
|
58
77
|
|
|
@@ -89,6 +108,14 @@ export default defineComponent({
|
|
|
89
108
|
component: LayerPanel,
|
|
90
109
|
slots: {},
|
|
91
110
|
};
|
|
111
|
+
case 'code-block':
|
|
112
|
+
return {
|
|
113
|
+
type: 'component',
|
|
114
|
+
icon: EditPen,
|
|
115
|
+
text: '代码编辑',
|
|
116
|
+
component: CodeBlockList,
|
|
117
|
+
slots: {},
|
|
118
|
+
};
|
|
92
119
|
default:
|
|
93
120
|
return undefined;
|
|
94
121
|
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-dialog
|
|
3
|
+
v-model="isShowCodeBlockEditor"
|
|
4
|
+
:title="currentTitle"
|
|
5
|
+
:fullscreen="true"
|
|
6
|
+
:before-close="saveAndClose"
|
|
7
|
+
:append-to-body="true"
|
|
8
|
+
custom-class="code-editor-dialog"
|
|
9
|
+
>
|
|
10
|
+
<layout v-model:left="left" :min-left="45" class="code-editor-layout">
|
|
11
|
+
<!-- 左侧列表 -->
|
|
12
|
+
<template #left v-if="mode === CodeEditorMode.LIST">
|
|
13
|
+
<el-tree
|
|
14
|
+
v-if="!isEmpty(state.codeList)"
|
|
15
|
+
ref="tree"
|
|
16
|
+
node-key="id"
|
|
17
|
+
empty-text="暂无代码块"
|
|
18
|
+
:data="state.codeList"
|
|
19
|
+
:highlight-current="true"
|
|
20
|
+
@node-click="selectHandler"
|
|
21
|
+
:current-node-key="state.codeList[0].id"
|
|
22
|
+
class="side-tree"
|
|
23
|
+
>
|
|
24
|
+
<template #default="{ data }">
|
|
25
|
+
<div :id="data.id" class="list-container">
|
|
26
|
+
<div class="list-item">
|
|
27
|
+
<div class="code-name">{{ data.name }}({{ data.id }})</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
31
|
+
</el-tree>
|
|
32
|
+
</template>
|
|
33
|
+
<!-- 右侧区域 -->
|
|
34
|
+
<template #center>
|
|
35
|
+
<div
|
|
36
|
+
v-if="!isEmpty(codeConfig)"
|
|
37
|
+
:class="[
|
|
38
|
+
mode === CodeEditorMode.LIST
|
|
39
|
+
? 'm-editor-code-block-editor-panel-list-mode'
|
|
40
|
+
: 'm-editor-code-block-editor-panel',
|
|
41
|
+
]"
|
|
42
|
+
>
|
|
43
|
+
<slot name="code-block-edit-panel-header" :id="id"></slot>
|
|
44
|
+
<el-card shadow="never">
|
|
45
|
+
<template #header>
|
|
46
|
+
<div class="code-name-wrapper">
|
|
47
|
+
<div class="code-name-label">代码块名称</div>
|
|
48
|
+
<el-input v-if="codeConfig" class="code-name-input" v-model="codeConfig.name" :disabled="!editable" />
|
|
49
|
+
</div>
|
|
50
|
+
</template>
|
|
51
|
+
<div class="m-editor-wrapper">
|
|
52
|
+
<magic-code-editor
|
|
53
|
+
v-if="codeConfig"
|
|
54
|
+
ref="codeEditor"
|
|
55
|
+
class="m-editor-container"
|
|
56
|
+
:init-values="`${codeConfig.content}`"
|
|
57
|
+
@save="saveCode"
|
|
58
|
+
:options="{
|
|
59
|
+
tabSize: 2,
|
|
60
|
+
fontSize: 16,
|
|
61
|
+
formatOnPaste: true,
|
|
62
|
+
readOnly: !editable,
|
|
63
|
+
}"
|
|
64
|
+
></magic-code-editor>
|
|
65
|
+
<div class="m-editor-content-bottom" v-if="editable">
|
|
66
|
+
<el-button type="primary" class="button" @click="saveCode">保存</el-button>
|
|
67
|
+
<el-button type="primary" class="button" @click="saveAndClose">关闭</el-button>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="m-editor-content-bottom" v-else>
|
|
70
|
+
<el-button type="primary" class="button" @click="saveAndClose">关闭</el-button>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</el-card>
|
|
74
|
+
</div>
|
|
75
|
+
</template>
|
|
76
|
+
</layout>
|
|
77
|
+
</el-dialog>
|
|
78
|
+
</template>
|
|
79
|
+
|
|
80
|
+
<script lang="ts" setup>
|
|
81
|
+
import { computed, inject, reactive, ref, watchEffect } from 'vue';
|
|
82
|
+
import { ElMessage } from 'element-plus';
|
|
83
|
+
import { forIn, isEmpty } from 'lodash-es';
|
|
84
|
+
import type * as monaco from 'monaco-editor';
|
|
85
|
+
|
|
86
|
+
import type { CodeBlockContent, CodeDslList, ListState, Services } from '../../../type';
|
|
87
|
+
import { CodeEditorMode } from '../../../type';
|
|
88
|
+
import MagicCodeEditor from '../../CodeEditor.vue';
|
|
89
|
+
import Layout from '../../Layout.vue';
|
|
90
|
+
|
|
91
|
+
const services = inject<Services>('services');
|
|
92
|
+
|
|
93
|
+
const codeEditor = ref<InstanceType<typeof MagicCodeEditor>>();
|
|
94
|
+
const left = ref(200);
|
|
95
|
+
const currentTitle = ref('');
|
|
96
|
+
// 编辑器当前需展示的代码块内容
|
|
97
|
+
const codeConfig = ref<CodeBlockContent | null>(null);
|
|
98
|
+
// select选择的内容(ListState)
|
|
99
|
+
const state = reactive<ListState>({
|
|
100
|
+
codeList: [],
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// 是否展示代码编辑区
|
|
104
|
+
const isShowCodeBlockEditor = computed(
|
|
105
|
+
() => (codeConfig.value && services?.codeBlockService.getCodeEditorShowStatus()) || false,
|
|
106
|
+
);
|
|
107
|
+
const mode = computed(() => services?.codeBlockService.getMode());
|
|
108
|
+
const id = computed(() => services?.codeBlockService.getId() || '');
|
|
109
|
+
const editable = computed(() => services?.codeBlockService.getEditStatus());
|
|
110
|
+
// 当前选中组件绑定的代码块id数组
|
|
111
|
+
const selectedIds = computed(() => services?.codeBlockService.getCombineIds() || []);
|
|
112
|
+
|
|
113
|
+
watchEffect(async () => {
|
|
114
|
+
codeConfig.value = (await services?.codeBlockService.getCodeContentById(id.value)) || null;
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
watchEffect(async () => {
|
|
118
|
+
const codeDsl = (await services?.codeBlockService.getCodeDslByIds(selectedIds.value)) || null;
|
|
119
|
+
if (!codeDsl) return;
|
|
120
|
+
state.codeList = [];
|
|
121
|
+
forIn(codeDsl, (value: CodeBlockContent, key: string) => {
|
|
122
|
+
state.codeList.push({
|
|
123
|
+
id: key,
|
|
124
|
+
name: value.name,
|
|
125
|
+
content: value.content,
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
currentTitle.value = state.codeList[0]?.name || '';
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// 保存代码
|
|
132
|
+
const saveCode = async (): Promise<boolean> => {
|
|
133
|
+
if (!codeEditor.value || !codeConfig.value || !editable.value) return true;
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
// 代码内容
|
|
137
|
+
const codeContent = (codeEditor.value.getEditor() as monaco.editor.IStandaloneCodeEditor)?.getValue();
|
|
138
|
+
/* eslint no-eval: "off" */
|
|
139
|
+
codeConfig.value.content = eval(codeContent);
|
|
140
|
+
} catch (e: any) {
|
|
141
|
+
ElMessage.error(e.stack);
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
// 存入dsl
|
|
145
|
+
await services?.codeBlockService.setCodeDslById(id.value, {
|
|
146
|
+
name: codeConfig.value.name,
|
|
147
|
+
content: codeConfig.value.content,
|
|
148
|
+
});
|
|
149
|
+
ElMessage.success('代码保存成功');
|
|
150
|
+
return true;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// 保存并关闭
|
|
154
|
+
const saveAndClose = async () => {
|
|
155
|
+
const saveRes = await saveCode();
|
|
156
|
+
if (saveRes) {
|
|
157
|
+
await services?.codeBlockService.setCodeEditorShowStatus(false);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const selectHandler = (data: CodeDslList) => {
|
|
162
|
+
services?.codeBlockService.setId(data.id);
|
|
163
|
+
currentTitle.value = data.name;
|
|
164
|
+
};
|
|
165
|
+
</script>
|