@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.
Files changed (101) hide show
  1. package/dist/style.css +41 -28
  2. package/dist/{tmagic-editor.mjs → tmagic-editor.js} +1693 -1272
  3. package/dist/tmagic-editor.js.map +1 -0
  4. package/dist/{tmagic-editor.umd.js → tmagic-editor.umd.cjs} +1700 -1274
  5. package/dist/tmagic-editor.umd.cjs.map +1 -0
  6. package/package.json +16 -14
  7. package/src/Editor.vue +54 -37
  8. package/src/components/CodeDraftEditor.vue +145 -0
  9. package/src/components/ContentMenu.vue +4 -4
  10. package/src/components/FunctionEditor.vue +145 -0
  11. package/src/components/Icon.vue +7 -5
  12. package/src/components/Layout.vue +149 -0
  13. package/src/components/ScrollBar.vue +1 -1
  14. package/src/components/ScrollViewer.vue +10 -1
  15. package/src/components/ToolButton.vue +30 -15
  16. package/src/fields/Code.vue +1 -1
  17. package/src/fields/CodeLink.vue +1 -1
  18. package/src/fields/CodeSelect.vue +89 -110
  19. package/src/fields/UISelect.vue +9 -8
  20. package/src/index.ts +1 -0
  21. package/src/layouts/AddPageBox.vue +3 -2
  22. package/src/layouts/CodeEditor.vue +2 -3
  23. package/src/layouts/Framework.vue +62 -40
  24. package/src/layouts/NavMenu.vue +1 -1
  25. package/src/layouts/PropsPanel.vue +11 -13
  26. package/src/layouts/Resizer.vue +1 -1
  27. package/src/layouts/sidebar/ComponentListPanel.vue +15 -13
  28. package/src/layouts/sidebar/LayerMenu.vue +9 -7
  29. package/src/layouts/sidebar/LayerPanel.vue +277 -177
  30. package/src/layouts/sidebar/Sidebar.vue +113 -27
  31. package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +34 -85
  32. package/src/layouts/sidebar/code-block/CodeBlockList.vue +55 -89
  33. package/src/layouts/workspace/Breadcrumb.vue +32 -0
  34. package/src/layouts/workspace/PageBar.vue +12 -11
  35. package/src/layouts/workspace/PageBarScrollContainer.vue +1 -1
  36. package/src/layouts/workspace/Stage.vue +26 -9
  37. package/src/layouts/workspace/ViewerMenu.vue +11 -9
  38. package/src/layouts/workspace/Workspace.vue +10 -3
  39. package/src/services/BaseService.ts +6 -1
  40. package/src/services/codeBlock.ts +124 -125
  41. package/src/services/componentList.ts +6 -1
  42. package/src/services/editor.ts +43 -19
  43. package/src/services/events.ts +6 -1
  44. package/src/services/history.ts +7 -16
  45. package/src/services/props.ts +7 -2
  46. package/src/services/storage.ts +1 -0
  47. package/src/services/ui.ts +12 -0
  48. package/src/theme/breadcrumb.scss +6 -0
  49. package/src/theme/code-block.scss +30 -21
  50. package/src/theme/component-list-panel.scss +3 -7
  51. package/src/theme/layer-panel.scss +7 -2
  52. package/src/theme/theme.scss +1 -0
  53. package/src/type.ts +76 -50
  54. package/src/utils/editor.ts +9 -1
  55. package/src/utils/index.ts +1 -0
  56. package/src/utils/props.ts +2 -2
  57. package/src/utils/scroll-viewer.ts +18 -2
  58. package/src/utils/stage.ts +9 -2
  59. package/types/Editor.vue.d.ts +42 -29
  60. package/types/components/CodeDraftEditor.vue.d.ts +148 -0
  61. package/types/components/ContentMenu.vue.d.ts +1 -3
  62. package/types/components/FunctionEditor.vue.d.ts +120 -0
  63. package/types/components/Icon.vue.d.ts +1 -3
  64. package/types/{layouts → components}/Layout.vue.d.ts +12 -1
  65. package/types/components/ScrollBar.vue.d.ts +1 -3
  66. package/types/components/ScrollViewer.vue.d.ts +45 -1
  67. package/types/components/ToolButton.vue.d.ts +1 -3
  68. package/types/fields/Code.vue.d.ts +1 -3
  69. package/types/fields/CodeLink.vue.d.ts +1 -3
  70. package/types/fields/CodeSelect.vue.d.ts +10 -12
  71. package/types/fields/UISelect.vue.d.ts +1 -3
  72. package/types/index.d.ts +1 -0
  73. package/types/layouts/AddPageBox.vue.d.ts +1 -3
  74. package/types/layouts/CodeEditor.vue.d.ts +6 -15
  75. package/types/layouts/NavMenu.vue.d.ts +1 -3
  76. package/types/layouts/sidebar/LayerMenu.vue.d.ts +25 -9
  77. package/types/layouts/sidebar/LayerPanel.vue.d.ts +38 -886
  78. package/types/layouts/sidebar/Sidebar.vue.d.ts +10 -5
  79. package/types/layouts/sidebar/code-block/CodeBlockEditor.vue.d.ts +1 -1
  80. package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +6 -5
  81. package/types/layouts/{sidebar/TabPane.vue.d.ts → workspace/Breadcrumb.vue.d.ts} +5 -43
  82. package/types/layouts/workspace/Stage.vue.d.ts +25 -8
  83. package/types/layouts/workspace/ViewerMenu.vue.d.ts +6 -3
  84. package/types/layouts/workspace/Workspace.vue.d.ts +23 -5
  85. package/types/services/BaseService.d.ts +2 -1
  86. package/types/services/codeBlock.d.ts +57 -36
  87. package/types/services/componentList.d.ts +1 -0
  88. package/types/services/editor.d.ts +5 -6
  89. package/types/services/events.d.ts +1 -0
  90. package/types/services/history.d.ts +5 -15
  91. package/types/services/props.d.ts +3 -2
  92. package/types/services/ui.d.ts +2 -1
  93. package/types/type.d.ts +64 -48
  94. package/types/utils/editor.d.ts +1 -0
  95. package/types/utils/index.d.ts +1 -0
  96. package/types/utils/props.d.ts +1 -1
  97. package/types/utils/scroll-viewer.d.ts +5 -0
  98. package/dist/tmagic-editor.mjs.map +0 -1
  99. package/dist/tmagic-editor.umd.js.map +0 -1
  100. package/src/layouts/Layout.vue +0 -100
  101. package/src/layouts/sidebar/TabPane.vue +0 -116
@@ -1,61 +1,147 @@
1
1
  <template>
2
- <el-tabs
2
+ <TMagicTabs
3
3
  v-if="data.type === 'tabs' && data.items.length"
4
4
  class="m-editor-sidebar"
5
5
  v-model="activeTabName"
6
6
  type="card"
7
7
  tab-position="left"
8
8
  >
9
- <tab-pane v-for="(item, index) in data.items" :key="index" :data="item">
10
- <template #layer-panel-header v-if="item === 'layer'">
11
- <slot name="layer-panel-header"></slot>
9
+ <component :is="uiComponent.component" v-for="(config, index) in sideBarItems" :key="index" :name="config.text">
10
+ <template #label>
11
+ <div :key="config.text">
12
+ <MIcon v-if="config.icon" :icon="config.icon"></MIcon>
13
+ <div v-if="config.text" class="magic-editor-tab-panel-title">{{ config.text }}</div>
14
+ </div>
12
15
  </template>
13
16
 
14
- <template #layer-node-content="{ node, data }" v-if="item === 'layer'">
15
- <slot name="layer-node-content" :data="data" :node="node"></slot>
16
- </template>
17
+ <component v-if="config" :is="config.component" v-bind="config.props || {}" v-on="config?.listeners || {}">
18
+ <template
19
+ #component-list-panel-header
20
+ v-if="config.$key === 'component-list' || config.slots?.componentListPanelHeader"
21
+ >
22
+ <slot v-if="config.$key === 'component-list'" name="component-list-panel-header"></slot>
23
+ <component v-else-if="config.slots?.componentListPanelHeader" :is="config.slots.componentListPanelHeader" />
24
+ </template>
17
25
 
18
- <template #component-list-panel-header v-if="item === 'component-list'">
19
- <slot name="component-list-panel-header"></slot>
20
- </template>
26
+ <template
27
+ #component-list-item="{ component }"
28
+ v-if="config.$key === 'component-list' || config.slots?.componentListItem"
29
+ >
30
+ <slot v-if="config.$key === 'component-list'" name="component-list-item" :component="component"></slot>
31
+ <component
32
+ v-else-if="config.slots?.componentListItem"
33
+ :is="config.slots.componentListItem"
34
+ :component="component"
35
+ />
36
+ </template>
21
37
 
22
- <template #component-list-item="{ component }" v-if="item === 'component-list'">
23
- <slot name="component-list-item" :component="component"></slot>
24
- </template>
38
+ <template #layer-panel-header v-if="config.$key === 'layer' || config.slots?.layerPanelHeader">
39
+ <slot v-if="config.$key === 'layer'" name="layer-panel-header"></slot>
40
+ <component v-else-if="config.slots?.layerPanelHeader" :is="config.slots.layerPanelHeader" />
41
+ </template>
25
42
 
26
- <template #code-block-panel-header v-if="item === 'code-block'">
27
- <slot name="code-block-panel-header"></slot>
28
- </template>
43
+ <template #code-block-panel-header v-if="config.$key === 'code-block' || config.slots?.codeBlockPanelHeader">
44
+ <slot v-if="config.$key === 'code-block'" name="code-block-panel-header"></slot>
45
+ <component v-else-if="config.slots?.codeBlockPanelHeader" :is="config.slots.codeBlockPanelHeader" />
46
+ </template>
29
47
 
30
- <template #code-block-panel-tool="{ id, data }" v-if="item === 'code-block'">
31
- <slot name="code-block-panel-tool" :id="id" :data="data"></slot>
32
- </template>
48
+ <template
49
+ #code-block-panel-tool="{ id, data }"
50
+ v-if="config.$key === 'code-block' || config.slots?.codeBlockPanelTool"
51
+ >
52
+ <slot v-if="config.$key === 'code-block'" name="code-block-panel-tool" :id="id" :data="data"></slot>
53
+ <component v-else-if="config.slots?.codeBlockPanelTool" :is="config.slots.codeBlockPanelTool" />
54
+ </template>
33
55
 
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>
37
- </tab-pane>
38
- </el-tabs>
56
+ <template
57
+ #code-block-edit-panel-header="{ id }"
58
+ v-if="config.$key === 'code-block' || config.slots?.codeBlockEditPanelHeader"
59
+ >
60
+ <slot v-if="config.$key === 'code-block'" name="code-block-edit-panel-header" :id="id"></slot>
61
+ <component v-else-if="config.slots?.codeBlockEditPanelHeader" :is="config.slots.codeBlockEditPanelHeader" />
62
+ </template>
63
+
64
+ <template
65
+ #layer-node-content="{ data: nodeData, node }"
66
+ v-if="config.$key === 'layer' || config.slots?.layerNodeContent"
67
+ >
68
+ <slot v-if="config.$key === 'layer'" name="layer-node-content" :data="nodeData" :node="node"></slot>
69
+ <component
70
+ v-else-if="config.slots?.layerNodeContent"
71
+ :is="config.slots.layerNodeContent"
72
+ :data="nodeData"
73
+ :node="node"
74
+ />
75
+ </template>
76
+ </component>
77
+ </component>
78
+ </TMagicTabs>
39
79
  </template>
40
80
 
41
- <script lang="ts" setup>
42
- import { ref, watch } from 'vue';
81
+ <script lang="ts" setup name="MEditorSidebar">
82
+ import { computed, ref, watch } from 'vue';
83
+ import { Coin, EditPen, Files } from '@element-plus/icons-vue';
84
+
85
+ import { getConfig, TMagicTabs } from '@tmagic/design';
43
86
 
87
+ import MIcon from '../../components/Icon.vue';
88
+ import type { MenuButton, MenuComponent, SideComponent, SideItem } from '../../type';
44
89
  import { SideBarData } from '../../type';
45
90
 
46
- import TabPane from './TabPane.vue';
91
+ import CodeBlockList from './code-block/CodeBlockList.vue';
92
+ import ComponentListPanel from './ComponentListPanel.vue';
93
+ import LayerPanel from './LayerPanel.vue';
47
94
 
48
95
  const props = withDefaults(
49
96
  defineProps<{
50
97
  data?: SideBarData;
98
+ layerContentMenu: (MenuButton | MenuComponent)[];
51
99
  }>(),
52
100
  {
53
101
  data: () => ({ type: 'tabs', status: '组件', items: ['component-list', 'layer', 'code-block'] }),
54
102
  },
55
103
  );
56
104
 
105
+ const uiComponent = getConfig('components').tabPane;
106
+
57
107
  const activeTabName = ref(props.data?.status);
58
108
 
109
+ const getItemConfig = (data: SideItem): SideComponent => {
110
+ const map: Record<string, SideComponent> = {
111
+ 'component-list': {
112
+ $key: 'component-list',
113
+ type: 'component',
114
+ icon: Coin,
115
+ text: '组件',
116
+ component: ComponentListPanel,
117
+ slots: {},
118
+ },
119
+ layer: {
120
+ $key: 'layer',
121
+ type: 'component',
122
+ icon: Files,
123
+ text: '已选组件',
124
+ props: {
125
+ layerContentMenu: props.layerContentMenu,
126
+ },
127
+ component: LayerPanel,
128
+ slots: {},
129
+ },
130
+ 'code-block': {
131
+ $key: 'code-block',
132
+ type: 'component',
133
+ icon: EditPen,
134
+ text: '代码编辑',
135
+ component: CodeBlockList,
136
+ slots: {},
137
+ },
138
+ };
139
+
140
+ return typeof data === 'string' ? map[data] : data;
141
+ };
142
+
143
+ const sideBarItems = computed(() => props.data.items.map((item) => getItemConfig(item)));
144
+
59
145
  watch(
60
146
  () => props.data.status,
61
147
  (status) => {
@@ -1,25 +1,25 @@
1
1
  <template>
2
- <el-dialog
3
- v-model="isShowCodeBlockEditor"
2
+ <TMagicDialog
3
+ :model-value="true"
4
4
  class="code-editor-dialog"
5
5
  :title="currentTitle"
6
6
  :fullscreen="true"
7
- :before-close="saveAndClose"
7
+ :close-on-press-escape="false"
8
8
  :append-to-body="true"
9
+ :show-close="false"
9
10
  >
10
- <layout v-model:left="left" :min-left="45" class="code-editor-layout">
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
- <el-tree
14
+ <TMagicTree
14
15
  v-if="!isEmpty(state.codeList)"
15
- ref="tree"
16
+ class="side-tree"
16
17
  node-key="id"
17
18
  empty-text="暂无代码块"
18
19
  :data="state.codeList"
19
20
  :highlight-current="true"
20
- @node-click="selectHandler"
21
21
  :current-node-key="state.codeList[0].id"
22
- class="side-tree"
22
+ @node-click="selectHandler"
23
23
  >
24
24
  <template #default="{ data }">
25
25
  <div :id="data.id" class="list-container">
@@ -28,7 +28,7 @@
28
28
  </div>
29
29
  </div>
30
30
  </template>
31
- </el-tree>
31
+ </TMagicTree>
32
32
  </template>
33
33
  <!-- 右侧区域 -->
34
34
  <template #center>
@@ -41,56 +41,37 @@
41
41
  ]"
42
42
  >
43
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>
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>
74
53
  </div>
75
54
  </template>
76
- </layout>
77
- </el-dialog>
55
+ </Layout>
56
+ </TMagicDialog>
78
57
  </template>
79
58
 
80
- <script lang="ts" setup>
59
+ <script lang="ts" setup name="MEditorCodeBlockEditor">
81
60
  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';
61
+ import { cloneDeep, forIn, isEmpty } from 'lodash-es';
85
62
 
86
- import type { CodeBlockContent, CodeDslList, ListState, Services } from '../../../type';
63
+ import { TMagicDialog, TMagicTree } from '@tmagic/design';
64
+ import { CodeBlockContent } from '@tmagic/schema';
65
+
66
+ import FunctionEditor from '../../../components/FunctionEditor.vue';
67
+ import Layout from '../../../components/Layout.vue';
68
+ import type { CodeDslItem, ListState, Services } from '../../../type';
87
69
  import { CodeEditorMode } from '../../../type';
88
- import MagicCodeEditor from '../../CodeEditor.vue';
89
- import Layout from '../../Layout.vue';
70
+ import { serializeConfig } from '../../../utils/editor';
90
71
 
91
72
  const services = inject<Services>('services');
73
+ const codeOptions = inject('codeOptions', {});
92
74
 
93
- const codeEditor = ref<InstanceType<typeof MagicCodeEditor>>();
94
75
  const left = ref(200);
95
76
  const currentTitle = ref('');
96
77
  // 编辑器当前需展示的代码块内容
@@ -100,10 +81,6 @@ const state = reactive<ListState>({
100
81
  codeList: [],
101
82
  });
102
83
 
103
- // 是否展示代码编辑区
104
- const isShowCodeBlockEditor = computed(
105
- () => (codeConfig.value && services?.codeBlockService.getCodeEditorShowStatus()) || false,
106
- );
107
84
  const mode = computed(() => services?.codeBlockService.getMode());
108
85
  const id = computed(() => services?.codeBlockService.getId() || '');
109
86
  const editable = computed(() => services?.codeBlockService.getEditStatus());
@@ -111,7 +88,9 @@ const editable = computed(() => services?.codeBlockService.getEditStatus());
111
88
  const selectedIds = computed(() => services?.codeBlockService.getCombineIds() || []);
112
89
 
113
90
  watchEffect(async () => {
114
- 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);
115
94
  });
116
95
 
117
96
  watchEffect(async () => {
@@ -127,37 +106,7 @@ watchEffect(async () => {
127
106
  currentTitle.value = state.codeList[0]?.name || '';
128
107
  });
129
108
 
130
- // 保存代码
131
- const saveCode = async (): Promise<boolean> => {
132
- if (!codeEditor.value || !codeConfig.value || !editable.value) return true;
133
-
134
- try {
135
- // 代码内容
136
- const codeContent = (codeEditor.value.getEditor() as monaco.editor.IStandaloneCodeEditor)?.getValue();
137
- /* eslint no-eval: "off" */
138
- codeConfig.value.content = eval(codeContent);
139
- } catch (e: any) {
140
- ElMessage.error(e.stack);
141
- return false;
142
- }
143
- // 存入dsl
144
- await services?.codeBlockService.setCodeDslById(id.value, {
145
- name: codeConfig.value.name,
146
- content: codeConfig.value.content,
147
- });
148
- ElMessage.success('代码保存成功');
149
- return true;
150
- };
151
-
152
- // 保存并关闭
153
- const saveAndClose = async () => {
154
- const saveRes = await saveCode();
155
- if (saveRes) {
156
- await services?.codeBlockService.setCodeEditorShowStatus(false);
157
- }
158
- };
159
-
160
- const selectHandler = (data: CodeDslList) => {
109
+ const selectHandler = (data: CodeDslItem) => {
161
110
  services?.codeBlockService.setId(data.id);
162
111
  currentTitle.value = data.name;
163
112
  };
@@ -2,22 +2,22 @@
2
2
  <div class="m-editor-code-block-list">
3
3
  <slot name="code-block-panel-header">
4
4
  <div class="code-header-wrapper">
5
- <el-input
5
+ <TMagicInput
6
6
  :class="[editable ? 'code-filter-input' : 'code-filter-input-no-btn']"
7
7
  size="small"
8
8
  placeholder="输入关键字进行过滤"
9
9
  clearable
10
10
  v-model="filterText"
11
11
  @input="filterTextChangeHandler"
12
- ></el-input>
13
- <el-button class="create-code-button" type="primary" size="small" @click="createCodeBlock" v-if="editable"
14
- >新增</el-button
12
+ ></TMagicInput>
13
+ <TMagicButton class="create-code-button" type="primary" size="small" @click="createCodeBlock" v-if="editable"
14
+ >新增</TMagicButton
15
15
  >
16
16
  </div>
17
17
  </slot>
18
18
 
19
19
  <!-- 代码块列表 -->
20
- <el-tree
20
+ <TMagicTree
21
21
  v-if="!isEmpty(state.codeList)"
22
22
  ref="tree"
23
23
  node-key="id"
@@ -30,30 +30,30 @@
30
30
  <template #default="{ data }">
31
31
  <div :id="data.id" class="list-container">
32
32
  <div class="list-item">
33
- <div class="code-name">{{ data.name }}({{ data.id }})</div>
33
+ <span class="code-name">{{ data.name }}({{ data.id }})</span>
34
34
  <!-- 右侧工具栏 -->
35
35
  <div class="right-tool">
36
- <el-tooltip effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
36
+ <TMagicTooltip effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
37
37
  <Icon :icon="editable ? Edit : View" class="edit-icon" @click.stop="editCode(`${data.id}`)"></Icon>
38
- </el-tooltip>
39
- <el-tooltip
38
+ </TMagicTooltip>
39
+ <TMagicTooltip
40
40
  effect="dark"
41
41
  content="查看绑定关系"
42
42
  placement="bottom"
43
- v-if="state.bindComps[data.id] && state.bindComps[data.id].length > 0"
43
+ v-if="data.combineInfo && data.combineInfo.length > 0"
44
44
  >
45
45
  <Icon :icon="Link" class="edit-icon" @click.stop="toggleCombineRelation(data)"></Icon>
46
- </el-tooltip>
47
- <el-tooltip effect="dark" content="删除" placement="bottom" v-if="editable">
46
+ </TMagicTooltip>
47
+ <TMagicTooltip effect="dark" content="删除" placement="bottom" v-if="editable">
48
48
  <Icon :icon="Close" class="edit-icon" @click.stop="deleteCode(`${data.id}`)"></Icon>
49
- </el-tooltip>
49
+ </TMagicTooltip>
50
50
  <slot name="code-block-panel-tool" :id="data.id" :data="data.codeBlockContent"></slot>
51
51
  </div>
52
52
  </div>
53
53
  <!-- 展示代码块下绑定的组件 -->
54
54
  <div
55
55
  class="code-comp-map-wrapper"
56
- v-if="data.showRelation && state.bindComps[data.id] && state.bindComps[data.id].length > 0"
56
+ v-if="data.showRelation && data.combineInfo && data.combineInfo.length > 0"
57
57
  >
58
58
  <svg class="arrow-left" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-029747aa="">
59
59
  <path
@@ -61,31 +61,22 @@
61
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
62
  ></path>
63
63
  </svg>
64
- <!-- todo 功能暂时隐藏 -->
65
- <!-- <el-button
66
- v-for="(comp, index) in state.bindComps[data.id]"
64
+ <TMagicButton
65
+ v-for="(comp, index) in data.combineInfo"
67
66
  :key="index"
68
67
  class="code-comp"
69
68
  size="small"
70
69
  :plain="true"
71
- >{{ comp.name }}<Icon :icon="Close" class="comp-delete-icon" @click.stop="unbind(comp.id, data.id)"></Icon
72
- ></el-button> -->
73
- <el-button
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 }}</el-button
70
+ @click.stop="selectComp(comp.compId)"
71
+ >{{ comp.compName }}</TMagicButton
81
72
  >
82
73
  </div>
83
74
  </div>
84
75
  </template>
85
- </el-tree>
76
+ </TMagicTree>
86
77
 
87
78
  <!-- 代码块编辑区 -->
88
- <code-block-editor>
79
+ <code-block-editor v-if="isShowCodeBlockEditor">
89
80
  <template #code-block-edit-panel-header="{ id }">
90
81
  <slot name="code-block-edit-panel-header" :id="id"></slot>
91
82
  </template>
@@ -93,69 +84,68 @@
93
84
  </div>
94
85
  </template>
95
86
 
96
- <script lang="ts" setup>
87
+ <script lang="ts" setup name="MEditorCodeBlockList">
97
88
  import { computed, inject, reactive, ref, watch } from 'vue';
98
89
  import { Close, Edit, Link, View } from '@element-plus/icons-vue';
99
- import { ElMessage } from 'element-plus';
100
- import { forIn, isEmpty } from 'lodash-es';
90
+ import { cloneDeep, forIn, isEmpty } from 'lodash-es';
101
91
 
102
- import { Id } from '@tmagic/schema';
92
+ import { TMagicButton, TMagicInput, tMagicMessage, TMagicTooltip, TMagicTree } from '@tmagic/design';
93
+ import { CodeBlockContent, Id } from '@tmagic/schema';
103
94
  import StageCore from '@tmagic/stage';
104
95
 
105
96
  import Icon from '../../../components/Icon.vue';
106
- import type { CodeBlockContent, CodeRelation, Services } from '../../../type';
107
- import { CodeDeleteErrorType, CodeDslList, CodeEditorMode, ListRelationState } from '../../../type';
97
+ import type { CodeRelation, Services } from '../../../type';
98
+ import { CodeDeleteErrorType, CodeDslItem, CodeEditorMode, ListState } from '../../../type';
108
99
 
109
100
  import codeBlockEditor from './CodeBlockEditor.vue';
110
101
 
111
102
  const props = defineProps<{
112
- customError?: (id: string, errorType: CodeDeleteErrorType) => any;
103
+ customError?: (id: Id, errorType: CodeDeleteErrorType) => any;
113
104
  }>();
114
105
 
115
106
  const services = inject<Services>('services');
116
107
 
117
108
  // 代码块列表
118
- const state = reactive<ListRelationState>({
109
+ const state = reactive<ListState>({
119
110
  codeList: [],
120
- bindComps: {},
121
111
  });
122
112
 
123
113
  const editable = computed(() => services?.codeBlockService.getEditStatus());
124
114
 
115
+ // 是否展示代码编辑区
116
+ const isShowCodeBlockEditor = computed(() => services?.codeBlockService.getCodeEditorShowStatus() || false);
117
+ // 获取绑定关系
118
+ const codeCombineInfo = ref<CodeRelation | null>(null);
119
+
125
120
  // 根据代码块ID获取其绑定的组件信息
126
- const getBindCompsByCodeId = (codeId: string, codeBlockContent: CodeBlockContent) => {
127
- if (isEmpty(codeBlockContent) || isEmpty(codeBlockContent.comps)) {
128
- state.bindComps[codeId] = [];
129
- return;
130
- }
131
- const compsField = codeBlockContent.comps as CodeRelation;
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),
121
+ const getBindCompsByCodeId = (codeId: Id) => {
122
+ if (!codeCombineInfo.value || !codeCombineInfo.value[codeId]) return [];
123
+ const bindCompsId = Object.keys(codeCombineInfo.value[codeId]);
124
+ return bindCompsId.map((compId) => ({
125
+ compId,
126
+ compName: getCompName(compId),
137
127
  }));
138
- state.bindComps[codeId] = compsInfo;
139
128
  };
140
129
 
141
130
  // 初始化代码块列表
142
131
  const initList = async () => {
143
- const codeDsl = (await services?.codeBlockService.getCodeDsl()) || null;
144
- if (!codeDsl) return;
132
+ const codeDsl = cloneDeep(await services?.codeBlockService.getCodeDsl()) || null;
133
+ codeCombineInfo.value = cloneDeep(services?.codeBlockService.getCombineInfo()) || null;
134
+ if (!codeDsl || !codeCombineInfo.value) return;
145
135
  state.codeList = [];
146
- forIn(codeDsl, (value: CodeBlockContent, codeId: string) => {
147
- getBindCompsByCodeId(codeId, value);
136
+ forIn(codeDsl, (value: CodeBlockContent, codeId: Id) => {
148
137
  state.codeList.push({
149
138
  id: codeId,
150
139
  name: value.name,
151
140
  codeBlockContent: value,
152
141
  showRelation: true,
142
+ combineInfo: getBindCompsByCodeId(codeId),
153
143
  });
154
144
  });
155
145
  };
156
146
 
157
147
  watch(
158
- () => services?.codeBlockService.getCodeDsl(),
148
+ [() => services?.codeBlockService.getCodeDslSync(), () => services?.codeBlockService.refreshCombineInfo()],
159
149
  () => {
160
150
  initList();
161
151
  },
@@ -165,31 +155,17 @@ watch(
165
155
  },
166
156
  );
167
157
 
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
158
  // 新增代码块
184
159
  const createCodeBlock = async () => {
185
160
  const { codeBlockService } = services || {};
186
161
  if (!codeBlockService) {
187
- ElMessage.error('新增代码块失败');
162
+ tMagicMessage.error('新增代码块失败');
188
163
  return;
189
164
  }
190
165
  const codeConfig: CodeBlockContent = {
191
166
  name: '代码块',
192
- content: `() => {\n // place your code here\n}`,
167
+ content: `({app, params}) => {\n // place your code here\n}`,
168
+ params: [],
193
169
  };
194
170
  await codeBlockService.setMode(CodeEditorMode.EDITOR);
195
171
  const id = await codeBlockService.getUniqueId();
@@ -198,14 +174,15 @@ const createCodeBlock = async () => {
198
174
  };
199
175
 
200
176
  // 编辑代码块
201
- const editCode = async (key: string) => {
177
+ const editCode = async (key: Id) => {
202
178
  await services?.codeBlockService.setMode(CodeEditorMode.EDITOR);
203
179
  services?.codeBlockService.setCodeEditorContent(true, key);
204
180
  };
205
181
 
206
182
  // 删除代码块
207
- const deleteCode = (key: string) => {
208
- const existBinds = !!(state.bindComps[key]?.length > 0);
183
+ const deleteCode = (key: Id) => {
184
+ const currentCode = state.codeList.find((codeItem: CodeDslItem) => codeItem.id === key);
185
+ const existBinds = !isEmpty(currentCode?.combineInfo);
209
186
  const undeleteableList = services?.codeBlockService.getUndeletableList() || [];
210
187
  if (!existBinds && !undeleteableList.includes(key)) {
211
188
  // 无绑定关系,且不在不可删除列表中
@@ -214,7 +191,7 @@ const deleteCode = (key: string) => {
214
191
  if (typeof props.customError === 'function') {
215
192
  props.customError(key, existBinds ? CodeDeleteErrorType.BIND : CodeDeleteErrorType.UNDELETEABLE);
216
193
  } else {
217
- ElMessage.error('代码块删除失败');
194
+ tMagicMessage.error('代码块删除失败');
218
195
  }
219
196
  }
220
197
  };
@@ -222,7 +199,7 @@ const deleteCode = (key: string) => {
222
199
  const filterText = ref('');
223
200
  const tree = ref();
224
201
 
225
- const filterNode = (value: string, data: CodeDslList): boolean => {
202
+ const filterNode = (value: string, data: CodeDslItem): boolean => {
226
203
  if (!value) {
227
204
  return true;
228
205
  }
@@ -234,7 +211,7 @@ const filterTextChangeHandler = (val: string) => {
234
211
  };
235
212
 
236
213
  // 展示/隐藏组件绑定关系
237
- const toggleCombineRelation = (data: CodeDslList) => {
214
+ const toggleCombineRelation = (data: CodeDslItem) => {
238
215
  const { id } = data;
239
216
  const currentCode = state.codeList.find((item) => item.id === id);
240
217
  if (!currentCode) return;
@@ -247,17 +224,6 @@ const getCompName = (compId: Id): string => {
247
224
  return node?.name || String(compId);
248
225
  };
249
226
 
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
227
  // 选中组件
262
228
  const selectComp = (compId: Id) => {
263
229
  const stage = services?.editorService.get<StageCore | null>('stage');