@tmagic/editor 1.3.0-alpha.2 → 1.3.0-alpha.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 (167) hide show
  1. package/dist/style.css +91 -120
  2. package/dist/tmagic-editor.js +4609 -3257
  3. package/dist/tmagic-editor.js.map +1 -1
  4. package/dist/tmagic-editor.umd.cjs +5708 -4337
  5. package/dist/tmagic-editor.umd.cjs.map +1 -1
  6. package/package.json +21 -22
  7. package/src/Editor.vue +29 -7
  8. package/src/components/CodeBlockEditor.vue +170 -0
  9. package/src/components/CodeParams.vue +60 -0
  10. package/src/components/ContentMenu.vue +30 -11
  11. package/src/components/Icon.vue +5 -1
  12. package/src/components/Resizer.vue +45 -0
  13. package/src/components/ScrollBar.vue +5 -1
  14. package/src/components/ScrollViewer.vue +5 -1
  15. package/src/components/SearchInput.vue +4 -0
  16. package/src/components/{Layout.vue → SplitView.vue} +8 -4
  17. package/src/components/ToolButton.vue +5 -1
  18. package/src/editorProps.ts +35 -4
  19. package/src/fields/Code.vue +28 -20
  20. package/src/fields/CodeLink.vue +15 -10
  21. package/src/fields/CodeSelect.vue +19 -10
  22. package/src/fields/CodeSelectCol.vue +67 -83
  23. package/src/fields/DataSourceFieldSelect.vue +47 -0
  24. package/src/fields/DataSourceFields.vue +24 -21
  25. package/src/fields/DataSourceInput.vue +318 -0
  26. package/src/fields/DataSourceMethodSelect.vue +136 -0
  27. package/src/fields/DataSourceMethods.vue +103 -0
  28. package/src/fields/DataSourceSelect.vue +68 -0
  29. package/src/fields/EventSelect.vue +62 -22
  30. package/src/fields/KeyValue.vue +13 -11
  31. package/src/fields/UISelect.vue +59 -15
  32. package/src/hooks/index.ts +21 -0
  33. package/src/hooks/use-code-block-edit.ts +84 -0
  34. package/src/hooks/use-data-source-method.ts +100 -0
  35. package/src/{utils/stage.ts → hooks/use-stage.ts} +4 -7
  36. package/src/icons/AppManageIcon.vue +5 -1
  37. package/src/icons/CenterIcon.vue +13 -0
  38. package/src/icons/CodeIcon.vue +5 -3
  39. package/src/index.ts +24 -3
  40. package/src/initService.ts +75 -16
  41. package/src/layouts/AddPageBox.vue +5 -1
  42. package/src/layouts/CodeEditor.vue +66 -11
  43. package/src/layouts/Framework.vue +32 -28
  44. package/src/layouts/NavMenu.vue +5 -1
  45. package/src/layouts/PropsPanel.vue +14 -4
  46. package/src/layouts/sidebar/ComponentListPanel.vue +11 -10
  47. package/src/layouts/sidebar/LayerMenu.vue +13 -25
  48. package/src/layouts/sidebar/LayerNode.vue +40 -0
  49. package/src/layouts/sidebar/LayerPanel.vue +71 -28
  50. package/src/layouts/sidebar/Sidebar.vue +13 -17
  51. package/src/layouts/sidebar/code-block/CodeBlockList.vue +84 -118
  52. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +63 -0
  53. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +39 -34
  54. package/src/layouts/sidebar/data-source/DataSourceList.vue +145 -0
  55. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +17 -65
  56. package/src/layouts/workspace/Breadcrumb.vue +5 -1
  57. package/src/layouts/workspace/PageBar.vue +5 -1
  58. package/src/layouts/workspace/PageBarScrollContainer.vue +5 -1
  59. package/src/layouts/workspace/Stage.vue +30 -8
  60. package/src/layouts/workspace/ViewerMenu.vue +15 -36
  61. package/src/layouts/workspace/Workspace.vue +9 -134
  62. package/src/services/codeBlock.ts +20 -72
  63. package/src/services/dataSource.ts +17 -2
  64. package/src/services/dep.ts +23 -20
  65. package/src/services/editor.ts +3 -3
  66. package/src/services/keybinding.ts +185 -0
  67. package/src/services/props.ts +2 -2
  68. package/src/services/storage.ts +3 -2
  69. package/src/theme/code-block.scss +5 -117
  70. package/src/theme/code-editor.scss +27 -2
  71. package/src/theme/content-menu.scss +1 -1
  72. package/src/theme/data-source-input.scss +18 -0
  73. package/src/theme/data-source-methods.scss +13 -0
  74. package/src/theme/event.scss +15 -12
  75. package/src/theme/framework.scss +0 -3
  76. package/src/theme/layer-panel.scss +6 -0
  77. package/src/theme/layout.scss +4 -0
  78. package/src/theme/resizer.scss +25 -10
  79. package/src/theme/stage.scss +4 -0
  80. package/src/theme/theme.scss +2 -0
  81. package/src/type.ts +105 -7
  82. package/src/utils/config.ts +1 -1
  83. package/src/utils/content-menu.ts +92 -0
  84. package/src/utils/data-source/formConfigs/base.ts +35 -30
  85. package/src/utils/data-source/index.ts +75 -6
  86. package/src/utils/dep.ts +39 -7
  87. package/src/utils/index.ts +1 -1
  88. package/src/utils/keybinding-config.ts +120 -0
  89. package/src/utils/props.ts +298 -155
  90. package/src/utils/undo-redo.ts +1 -1
  91. package/types/Editor.vue.d.ts +37 -4
  92. package/types/components/CodeBlockEditor.vue.d.ts +23 -0
  93. package/types/components/CodeParams.vue.d.ts +26 -0
  94. package/types/components/ContentMenu.vue.d.ts +8 -3
  95. package/types/components/Icon.vue.d.ts +2 -2
  96. package/types/{layouts → components}/Resizer.vue.d.ts +2 -2
  97. package/types/components/ScrollBar.vue.d.ts +1 -1
  98. package/types/components/ScrollViewer.vue.d.ts +8 -5
  99. package/types/components/SearchInput.vue.d.ts +1 -1
  100. package/types/components/{Layout.vue.d.ts → SplitView.vue.d.ts} +9 -6
  101. package/types/components/ToolButton.vue.d.ts +10 -7
  102. package/types/editorProps.d.ts +23 -4
  103. package/types/fields/Code.vue.d.ts +23 -18
  104. package/types/fields/CodeLink.vue.d.ts +13 -22
  105. package/types/fields/CodeSelect.vue.d.ts +12 -20
  106. package/types/fields/CodeSelectCol.vue.d.ts +14 -15
  107. package/types/fields/DataSourceFieldSelect.vue.d.ts +29 -0
  108. package/types/fields/DataSourceFields.vue.d.ts +13 -21
  109. package/types/fields/DataSourceInput.vue.d.ts +34 -0
  110. package/types/fields/DataSourceMethodSelect.vue.d.ts +29 -0
  111. package/types/fields/DataSourceMethods.vue.d.ts +32 -0
  112. package/types/fields/DataSourceSelect.vue.d.ts +40 -0
  113. package/types/fields/EventSelect.vue.d.ts +3 -14
  114. package/types/fields/KeyValue.vue.d.ts +15 -27
  115. package/types/fields/UISelect.vue.d.ts +3 -12
  116. package/types/hooks/index.d.ts +3 -0
  117. package/types/hooks/use-code-block-edit.d.ts +125 -0
  118. package/types/hooks/use-data-source-method.d.ts +123 -0
  119. package/types/icons/AppManageIcon.vue.d.ts +1 -1
  120. package/types/icons/CenterIcon.vue.d.ts +2 -0
  121. package/types/icons/CodeIcon.vue.d.ts +1 -1
  122. package/types/index.d.ts +12 -2
  123. package/types/initService.d.ts +2 -2
  124. package/types/layouts/AddPageBox.vue.d.ts +1 -1
  125. package/types/layouts/CodeEditor.vue.d.ts +18 -10
  126. package/types/layouts/Framework.vue.d.ts +11 -32
  127. package/types/layouts/NavMenu.vue.d.ts +7 -4
  128. package/types/layouts/PropsPanel.vue.d.ts +276 -4
  129. package/types/layouts/sidebar/ComponentListPanel.vue.d.ts +4 -4
  130. package/types/layouts/sidebar/LayerMenu.vue.d.ts +2 -2
  131. package/types/layouts/sidebar/LayerNode.vue.d.ts +16 -0
  132. package/types/layouts/sidebar/LayerPanel.vue.d.ts +5 -5
  133. package/types/layouts/sidebar/Sidebar.vue.d.ts +16 -16
  134. package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +7 -12
  135. package/types/layouts/sidebar/code-block/CodeBlockListPanel.vue.d.ts +28 -0
  136. package/types/layouts/sidebar/data-source/DataSourceConfigPanel.vue.d.ts +4 -2
  137. package/types/layouts/sidebar/data-source/DataSourceList.vue.d.ts +14 -0
  138. package/types/layouts/sidebar/data-source/DataSourceListPanel.vue.d.ts +1 -11
  139. package/types/layouts/workspace/Breadcrumb.vue.d.ts +1 -1
  140. package/types/layouts/workspace/PageBar.vue.d.ts +5 -5
  141. package/types/layouts/workspace/PageBarScrollContainer.vue.d.ts +2 -2
  142. package/types/layouts/workspace/Stage.vue.d.ts +2 -2
  143. package/types/layouts/workspace/ViewerMenu.vue.d.ts +7 -4
  144. package/types/layouts/workspace/Workspace.vue.d.ts +9 -9
  145. package/types/services/codeBlock.d.ts +6 -37
  146. package/types/services/dataSource.d.ts +7 -1
  147. package/types/services/dep.d.ts +12 -21
  148. package/types/services/editor.d.ts +1 -1
  149. package/types/services/keybinding.d.ts +20 -0
  150. package/types/services/props.d.ts +10 -115
  151. package/types/type.d.ts +97 -7
  152. package/types/utils/config.d.ts +1 -1
  153. package/types/utils/content-menu.d.ts +7 -0
  154. package/types/utils/data-source/formConfigs/base.d.ts +2 -2
  155. package/types/utils/data-source/index.d.ts +7 -1
  156. package/types/utils/dep.d.ts +4 -2
  157. package/types/utils/index.d.ts +1 -1
  158. package/types/utils/keybinding-config.d.ts +3 -0
  159. package/types/utils/props.d.ts +13 -102
  160. package/src/components/CodeDraftEditor.vue +0 -144
  161. package/src/components/FunctionEditor.vue +0 -190
  162. package/src/layouts/Resizer.vue +0 -32
  163. package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +0 -96
  164. package/types/components/CodeDraftEditor.vue.d.ts +0 -58
  165. package/types/components/FunctionEditor.vue.d.ts +0 -192
  166. package/types/layouts/sidebar/code-block/CodeBlockEditor.vue.d.ts +0 -25
  167. /package/types/{utils/stage.d.ts → hooks/use-stage.d.ts} +0 -0
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <div>
3
+ {{ `${data.name} (${data.id})` }}
4
+ </div>
5
+ <div class="layer-node-tool">
6
+ <template v-if="data.type !== 'page'">
7
+ <el-icon v-if="data.visible === false" @click.stop="setNodeVisible(true)" title="点击显示">
8
+ <Hide />
9
+ </el-icon>
10
+ <el-icon v-else @click.stop="setNodeVisible(false)" class="node-lock" title="点击隐藏">
11
+ <View />
12
+ </el-icon>
13
+ </template>
14
+ </div>
15
+ </template>
16
+
17
+ <script lang="ts" setup>
18
+ import { inject } from 'vue';
19
+ import { Hide, View } from '@element-plus/icons-vue';
20
+
21
+ import { MNode } from '@tmagic/schema';
22
+
23
+ import { Services } from '@editor/type';
24
+
25
+ const props = defineProps<{
26
+ data: MNode;
27
+ }>();
28
+
29
+ const services = inject<Services>('services');
30
+ const editorService = services?.editorService;
31
+
32
+ const setNodeVisible = (visible: boolean) => {
33
+ if (!editorService) return;
34
+
35
+ editorService.update({
36
+ id: props.data.id,
37
+ visible,
38
+ });
39
+ };
40
+ </script>
@@ -10,6 +10,7 @@
10
10
  ref="tree"
11
11
  node-key="id"
12
12
  empty-text="页面空荡荡的"
13
+ tabindex="-1"
13
14
  draggable
14
15
  :default-expanded-keys="expandedKeys"
15
16
  :default-checked-keys="checkedKeys"
@@ -34,9 +35,7 @@
34
35
  <template #default="{ node, data }">
35
36
  <div class="cus-tree-node" :id="data.id" @mouseenter="highlightHandler(data)">
36
37
  <slot name="layer-node-content" :node="node" :data="data">
37
- <span>
38
- {{ `${data.name} (${data.id})` }}
39
- </span>
38
+ <LayerNode :data="data"></LayerNode>
40
39
  </slot>
41
40
  </div>
42
41
  </template>
@@ -48,9 +47,8 @@
48
47
  </TMagicScrollbar>
49
48
  </template>
50
49
 
51
- <script lang="ts" setup name="MEditorLayerPanel">
52
- import { computed, inject, onMounted, onUnmounted, ref, watch } from 'vue';
53
- import KeyController from 'keycon';
50
+ <script lang="ts" setup>
51
+ import { computed, inject, onBeforeUnmount, onMounted, onUnmounted, ref, watch } from 'vue';
54
52
  import { difference, throttle, union } from 'lodash-es';
55
53
 
56
54
  import { TMagicScrollbar, TMagicTree } from '@tmagic/design';
@@ -63,6 +61,11 @@ import type { MenuButton, MenuComponent, Services } from '@editor/type';
63
61
  import { Layout } from '@editor/type';
64
62
 
65
63
  import LayerMenu from './LayerMenu.vue';
64
+ import LayerNode from './LayerNode.vue';
65
+
66
+ defineOptions({
67
+ name: 'MEditorLayerPanel',
68
+ });
66
69
 
67
70
  defineProps<{
68
71
  layerContentMenu: (MenuButton | MenuComponent)[];
@@ -71,6 +74,7 @@ defineProps<{
71
74
  const throttleTime = 150;
72
75
  const services = inject<Services>('services');
73
76
  const editorService = services?.editorService;
77
+ const keybindingService = services?.keybindingService;
74
78
 
75
79
  const tree = ref<InstanceType<typeof TMagicTree>>();
76
80
  const menu = ref<InstanceType<typeof LayerMenu>>();
@@ -152,7 +156,7 @@ const handleDragEnd = async (e: any) => {
152
156
  if (!tree.value) return;
153
157
  const { data: node } = e;
154
158
  const parent = editorService?.getParentById(node.id, false) as MContainer;
155
- const layout = await editorService?.getLayout(parent);
159
+ const layout = await editorService?.getLayout(parent, node);
156
160
  node.style.position = layout;
157
161
  if (layout === Layout.RELATIVE) {
158
162
  node.style.top = 0;
@@ -242,34 +246,69 @@ const windowBlurHandler = () => {
242
246
  isCtrlKeyDown.value = false;
243
247
  };
244
248
 
245
- let keycon: KeyController;
249
+ keybindingService?.registeCommand('layer-panel-not-ctrl-keydown', (e) => {
250
+ if (e.key !== keybindingService.ctrlKey) {
251
+ isCtrlKeyDown.value = false;
252
+ }
253
+ });
254
+
255
+ keybindingService?.registeCommand('layer-panel-ctrl-keydown', () => {
256
+ isCtrlKeyDown.value = true;
257
+ });
258
+
259
+ keybindingService?.registeCommand('layer-panel-ctrl-keyup', () => {
260
+ isCtrlKeyDown.value = false;
261
+ });
262
+
263
+ keybindingService?.registeCommand('layer-panel-global-keydwon', () => {
264
+ if (!tree.value?.$el.contains(document.activeElement)) {
265
+ isCtrlKeyDown.value = false;
266
+ }
267
+ });
268
+
269
+ keybindingService?.registe([
270
+ {
271
+ command: 'layer-panel-not-ctrl-keydown',
272
+ when: [['layer-panel', 'keydown']],
273
+ },
274
+ {
275
+ command: 'layer-panel-ctrl-keydown',
276
+ keybinding: 'ctrl',
277
+ when: [['layer-panel', 'keydown']],
278
+ },
279
+ {
280
+ command: 'layer-panel-ctrl-keyup',
281
+ keybinding: 'ctrl',
282
+ when: [['layer-panel', 'keyup']],
283
+ },
284
+ {
285
+ command: 'layer-panel-global-keydwon',
286
+ keybinding: 'ctrl',
287
+ when: [['global', 'keydown']],
288
+ },
289
+ ]);
290
+
291
+ watch(tree, () => {
292
+ if (tree.value?.$el) {
293
+ keybindingService?.registeEl('layer-panel', tree.value.$el);
294
+
295
+ tree.value.$el.addEventListener('blur', windowBlurHandler);
296
+ } else {
297
+ keybindingService?.unregisteEl('layer-panel');
298
+ }
299
+ });
246
300
 
247
301
  onMounted(() => {
248
302
  editorService?.on('remove', editorServiceRemoveHandler);
249
303
 
250
- keycon = new KeyController();
251
- const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
252
- const ctrl = isMac ? 'meta' : 'ctrl';
253
-
254
- keycon
255
- .keydown((e) => {
256
- if (e.key !== ctrl) {
257
- isCtrlKeyDown.value = false;
258
- }
259
- })
260
- .keydown(ctrl, () => {
261
- isCtrlKeyDown.value = true;
262
- })
263
- .keyup(ctrl, () => {
264
- isCtrlKeyDown.value = false;
265
- });
266
-
267
304
  globalThis.addEventListener('blur', windowBlurHandler);
268
305
  });
269
306
 
270
- onUnmounted(() => {
271
- keycon.destroy();
307
+ onBeforeUnmount(() => {
308
+ tree.value?.$el.removeEventListener('blur', windowBlurHandler);
309
+ });
272
310
 
311
+ onUnmounted(() => {
273
312
  editorService?.off('remove', editorServiceRemoveHandler);
274
313
  globalThis.removeEventListener('blur', windowBlurHandler);
275
314
  });
@@ -310,7 +349,11 @@ const clickHandler = (data: MNode): void => {
310
349
  // 右键菜单
311
350
  const contextmenu = async (event: MouseEvent, data: MNode): Promise<void> => {
312
351
  event.preventDefault();
313
- await select(data);
352
+
353
+ if (nodes.value.length < 2) {
354
+ await select(data);
355
+ }
356
+
314
357
  menu.value?.show(event);
315
358
  };
316
359
  </script>
@@ -3,13 +3,13 @@
3
3
  v-if="data.type === 'tabs' && data.items.length"
4
4
  v-model="activeTabName"
5
5
  class="m-editor-sidebar tmagic-design-tabs"
6
- v-bind="tabsComponent.props({ type: 'card', tabPosition: 'left' })"
7
- :is="tabsComponent.component"
6
+ v-bind="tabsComponent?.props({ type: 'card', tabPosition: 'left' }) || {}"
7
+ :is="tabsComponent?.component || 'el-tabs'"
8
8
  >
9
9
  <component
10
10
  v-for="(config, index) in sideBarItems"
11
- v-bind="tabPaneComponent.props({ name: config.text })"
12
- :is="tabPaneComponent.component"
11
+ v-bind="tabPaneComponent?.props({ name: config.text, lazy: config.lazy }) || {}"
12
+ :is="tabPaneComponent?.component || 'el-tab-pane'"
13
13
  :key="config.$key || index"
14
14
  >
15
15
  <template #label>
@@ -58,14 +58,6 @@
58
58
  <component v-else-if="config.slots?.codeBlockPanelTool" :is="config.slots.codeBlockPanelTool" />
59
59
  </template>
60
60
 
61
- <template
62
- #code-block-edit-panel-header="{ id }"
63
- v-if="config.$key === 'code-block' || config.slots?.codeBlockEditPanelHeader"
64
- >
65
- <slot v-if="config.$key === 'code-block'" name="code-block-edit-panel-header" :id="id"></slot>
66
- <component v-else-if="config.slots?.codeBlockEditPanelHeader" :is="config.slots.codeBlockEditPanelHeader" />
67
- </template>
68
-
69
61
  <template
70
62
  #layer-node-content="{ data: nodeData, node }"
71
63
  v-if="config.$key === 'layer' || config.slots?.layerNodeContent"
@@ -83,7 +75,7 @@
83
75
  </component>
84
76
  </template>
85
77
 
86
- <script lang="ts" setup name="MEditorSidebar">
78
+ <script lang="ts" setup>
87
79
  import { computed, ref, watch } from 'vue';
88
80
  import { Coin, EditPen, Goods, List } from '@element-plus/icons-vue';
89
81
 
@@ -93,11 +85,15 @@ import MIcon from '@editor/components/Icon.vue';
93
85
  import type { MenuButton, MenuComponent, SideComponent, SideItem } from '@editor/type';
94
86
  import { SideBarData } from '@editor/type';
95
87
 
96
- import CodeBlockList from './code-block/CodeBlockList.vue';
88
+ import CodeBlockListPanel from './code-block/CodeBlockListPanel.vue';
97
89
  import DataSourceListPanel from './data-source/DataSourceListPanel.vue';
98
90
  import ComponentListPanel from './ComponentListPanel.vue';
99
91
  import LayerPanel from './LayerPanel.vue';
100
92
 
93
+ defineOptions({
94
+ name: 'MEditorSidebar',
95
+ });
96
+
101
97
  const props = withDefaults(
102
98
  defineProps<{
103
99
  data: SideBarData;
@@ -108,8 +104,8 @@ const props = withDefaults(
108
104
  },
109
105
  );
110
106
 
111
- const tabPaneComponent = getConfig('components').tabPane;
112
- const tabsComponent = getConfig('components').tabs;
107
+ const tabPaneComponent = getConfig('components')?.tabPane;
108
+ const tabsComponent = getConfig('components')?.tabs;
113
109
 
114
110
  const activeTabName = ref(props.data?.status);
115
111
 
@@ -139,7 +135,7 @@ const getItemConfig = (data: SideItem): SideComponent => {
139
135
  type: 'component',
140
136
  icon: EditPen,
141
137
  text: '代码编辑',
142
- component: CodeBlockList,
138
+ component: CodeBlockListPanel,
143
139
  slots: {},
144
140
  },
145
141
  'data-source': {
@@ -1,92 +1,75 @@
1
1
  <template>
2
- <TMagicScrollbar class="m-editor-code-block-list m-editor-dep-list-panel">
3
- <slot name="code-block-panel-header">
4
- <div class="search-wrapper">
5
- <SearchInput @search="filterTextChangeHandler"></SearchInput>
6
- <TMagicButton class="create-code-button" type="primary" size="small" @click="createCodeBlock" v-if="editable"
7
- >新增</TMagicButton
8
- >
9
- </div>
10
- </slot>
11
-
12
- <!-- 代码块列表 -->
13
- <TMagicTree
14
- ref="tree"
15
- class="magic-editor-layer-tree"
16
- node-key="id"
17
- empty-text="暂无代码块"
18
- :default-expanded-keys="expandedKeys"
19
- :expand-on-click-node="false"
20
- :data="codeList"
21
- :props="treeProps"
22
- :highlight-current="true"
23
- :filter-node-method="filterNode"
24
- @node-click="clickHandler"
25
- >
26
- <template #default="{ data }">
27
- <div :id="data.id" class="list-container">
28
- <div class="list-item">
29
- <CodeIcon v-if="data.type === 'code'" class="codeIcon"></CodeIcon>
30
- <AppManageIcon v-if="data.type === 'node'" class="compIcon"></AppManageIcon>
31
- <span class="name" :class="{ code: data.type === 'code', hook: data.type === 'key' }"
32
- >{{ data.name }} ({{ data.id }})</span
33
- >
34
- <!-- 右侧工具栏 -->
35
- <div class="right-tool" v-if="data.type === 'code'">
36
- <TMagicTooltip effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
37
- <Icon :icon="editable ? Edit : View" class="edit-icon" @click.stop="editCode(`${data.id}`)"></Icon>
38
- </TMagicTooltip>
39
- <TMagicTooltip effect="dark" content="删除" placement="bottom" v-if="editable">
40
- <Icon :icon="Close" class="edit-icon" @click.stop="deleteCode(`${data.id}`)"></Icon>
41
- </TMagicTooltip>
42
- <slot name="code-block-panel-tool" :id="data.id" :data="data.codeBlockContent"></slot>
43
- </div>
2
+ <TMagicTree
3
+ ref="tree"
4
+ class="magic-editor-layer-tree"
5
+ node-key="id"
6
+ empty-text="暂无代码块"
7
+ :default-expanded-keys="expandedKeys"
8
+ :expand-on-click-node="false"
9
+ :data="codeList"
10
+ :props="{
11
+ children: 'children',
12
+ label: 'name',
13
+ value: 'id',
14
+ }"
15
+ :highlight-current="true"
16
+ :filter-node-method="filterNode"
17
+ @node-click="clickHandler"
18
+ >
19
+ <template #default="{ data }">
20
+ <div :id="data.id" class="list-container">
21
+ <div class="list-item">
22
+ <CodeIcon v-if="data.type === 'code'" class="codeIcon"></CodeIcon>
23
+ <AppManageIcon v-if="data.type === 'node'" class="compIcon"></AppManageIcon>
24
+ <span class="name" :class="{ code: data.type === 'code', hook: data.type === 'key' }"
25
+ >{{ data.name }} ({{ data.id }})</span
26
+ >
27
+ <!-- 右侧工具栏 -->
28
+ <div class="right-tool" v-if="data.type === 'code'">
29
+ <TMagicTooltip effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
30
+ <Icon :icon="editable ? Edit : View" class="edit-icon" @click.stop="editCode(data.id)"></Icon>
31
+ </TMagicTooltip>
32
+ <TMagicTooltip v-if="editable" effect="dark" content="删除" placement="bottom">
33
+ <Icon :icon="Close" class="edit-icon" @click.stop="deleteCode(`${data.id}`)"></Icon>
34
+ </TMagicTooltip>
35
+ <slot name="code-block-panel-tool" :id="data.id" :data="data.codeBlockContent"></slot>
44
36
  </div>
45
37
  </div>
46
- </template>
47
- </TMagicTree>
48
-
49
- <!-- 代码块编辑区 -->
50
- <CodeBlockEditor v-if="isShowCodeBlockEditor" :paramsColConfig="paramsColConfig">
51
- <template #code-block-edit-panel-header="{ id }">
52
- <slot name="code-block-edit-panel-header" :id="id"></slot>
53
- </template>
54
- </CodeBlockEditor>
55
- </TMagicScrollbar>
38
+ </div>
39
+ </template>
40
+ </TMagicTree>
56
41
  </template>
57
42
 
58
- <script setup lang="ts" name="MEditorCodeBlockList">
43
+ <script lang="ts" setup>
59
44
  import { computed, inject, ref } from 'vue';
60
45
  import { Close, Edit, View } from '@element-plus/icons-vue';
61
46
 
62
- import { TMagicButton, tMagicMessage, TMagicScrollbar, TMagicTooltip, TMagicTree } from '@tmagic/design';
63
- import { ColumnConfig } from '@tmagic/form';
64
- import { CodeBlockContent, Id } from '@tmagic/schema';
47
+ import { tMagicMessage, tMagicMessageBox, TMagicTooltip, TMagicTree } from '@tmagic/design';
48
+ import type { Id } from '@tmagic/schema';
65
49
 
66
50
  import Icon from '@editor/components/Icon.vue';
67
- import SearchInput from '@editor/components/SearchInput.vue';
68
51
  import AppManageIcon from '@editor/icons/AppManageIcon.vue';
69
52
  import CodeIcon from '@editor/icons/CodeIcon.vue';
70
- import { CodeDeleteErrorType, CodeDslItem, Services } from '@editor/type';
53
+ import { CodeDeleteErrorType, CodeDslItem, DepTargetType, Services } from '@editor/type';
71
54
 
72
- import CodeBlockEditor from './CodeBlockEditor.vue';
55
+ defineOptions({
56
+ name: 'MEditorCodeBlockList',
57
+ });
73
58
 
74
59
  const props = defineProps<{
75
60
  customError?: (id: Id, errorType: CodeDeleteErrorType) => any;
76
- paramsColConfig?: ColumnConfig;
77
61
  }>();
78
62
 
79
- const treeProps = {
80
- children: 'children',
81
- label: 'name',
82
- value: 'id',
83
- };
63
+ const emit = defineEmits<{
64
+ edit: [id: string];
65
+ remove: [id: string];
66
+ }>();
84
67
 
85
68
  const { codeBlockService, depService, editorService } = inject<Services>('services') || {};
86
69
 
87
70
  // 代码块列表
88
71
  const codeList = computed(() =>
89
- Object.values(depService?.targets['code-block'] || {}).map((target) => {
72
+ Object.values(depService?.getTargets(DepTargetType.CODE_BLOCK) || {}).map((target) => {
90
73
  // 组件节点
91
74
  const compNodes = Object.entries(target.deps).map(([id, dep]) => ({
92
75
  name: dep.name,
@@ -103,58 +86,10 @@ const codeList = computed(() =>
103
86
  };
104
87
  }),
105
88
  );
106
-
107
89
  // 默认展开组件层级的节点
108
90
  const expandedKeys = computed(() => codeList.value.map((item) => item.id));
109
-
110
91
  const editable = computed(() => codeBlockService?.getEditStatus());
111
92
 
112
- // 是否展示代码编辑区
113
- const isShowCodeBlockEditor = computed(() => codeBlockService?.getCodeEditorShowStatus() || false);
114
-
115
- // 新增代码块
116
- const createCodeBlock = async () => {
117
- if (!codeBlockService) {
118
- tMagicMessage.error('新增代码块失败');
119
- return;
120
- }
121
-
122
- const codeConfig: CodeBlockContent = {
123
- name: '代码块',
124
- content: `({app, params}) => {\n // place your code here\n}`,
125
- params: [],
126
- };
127
-
128
- const id = await codeBlockService.getUniqueId();
129
-
130
- await codeBlockService.setCodeDslById(id, codeConfig);
131
- codeBlockService.setCodeEditorContent(true, id);
132
- };
133
-
134
- // 编辑代码块
135
- const editCode = async (key: Id) => {
136
- codeBlockService?.setCodeEditorContent(true, key);
137
- };
138
-
139
- // 删除代码块
140
- const deleteCode = (key: Id) => {
141
- const currentCode = codeList.value.find((codeItem) => codeItem.id === key);
142
- const existBinds = Boolean(currentCode?.children.length);
143
- const undeleteableList = codeBlockService?.getUndeletableList() || [];
144
- if (!existBinds && !undeleteableList.includes(key)) {
145
- // 无绑定关系,且不在不可删除列表中
146
- codeBlockService?.deleteCodeDslByIds([key]);
147
- } else {
148
- if (typeof props.customError === 'function') {
149
- props.customError(key, existBinds ? CodeDeleteErrorType.BIND : CodeDeleteErrorType.UNDELETEABLE);
150
- } else {
151
- tMagicMessage.error('代码块删除失败');
152
- }
153
- }
154
- };
155
-
156
- const tree = ref<InstanceType<typeof TMagicTree>>();
157
-
158
93
  const filterNode = (value: string, data: CodeDslItem): boolean => {
159
94
  if (!value) {
160
95
  return true;
@@ -162,10 +97,6 @@ const filterNode = (value: string, data: CodeDslItem): boolean => {
162
97
  return `${data.name}${data.id}`.toLocaleLowerCase().indexOf(value.toLocaleLowerCase()) !== -1;
163
98
  };
164
99
 
165
- const filterTextChangeHandler = (val: string) => {
166
- tree.value?.filter(val);
167
- };
168
-
169
100
  // 选中组件
170
101
  const selectComp = (compId: Id) => {
171
102
  const stage = editorService?.get('stage');
@@ -180,4 +111,39 @@ const clickHandler = (data: any, node: any) => {
180
111
  selectComp(node.parent.data.id);
181
112
  }
182
113
  };
114
+
115
+ // 编辑代码块
116
+ const editCode = (id: string) => {
117
+ emit('edit', id);
118
+ };
119
+
120
+ const deleteCode = async (id: string) => {
121
+ const currentCode = codeList.value.find((codeItem) => codeItem.id === id);
122
+ const existBinds = Boolean(currentCode?.children.length);
123
+ const undeleteableList = codeBlockService?.getUndeletableList() || [];
124
+ if (!existBinds && !undeleteableList.includes(id)) {
125
+ await tMagicMessageBox.confirm('确定删除该代码块吗?', '提示', {
126
+ confirmButtonText: '确定',
127
+ cancelButtonText: '取消',
128
+ type: 'warning',
129
+ });
130
+
131
+ // 无绑定关系,且不在不可删除列表中
132
+ emit('remove', id);
133
+ } else {
134
+ if (typeof props.customError === 'function') {
135
+ props.customError(id, existBinds ? CodeDeleteErrorType.BIND : CodeDeleteErrorType.UNDELETEABLE);
136
+ } else {
137
+ tMagicMessage.error('代码块删除失败');
138
+ }
139
+ }
140
+ };
141
+
142
+ const tree = ref<InstanceType<typeof TMagicTree>>();
143
+
144
+ defineExpose({
145
+ filter(val: string) {
146
+ tree.value?.filter(val);
147
+ },
148
+ });
183
149
  </script>
@@ -0,0 +1,63 @@
1
+ <template>
2
+ <TMagicScrollbar class="m-editor-code-block-list m-editor-dep-list-panel">
3
+ <slot name="code-block-panel-header">
4
+ <div class="search-wrapper">
5
+ <SearchInput @search="filterTextChangeHandler"></SearchInput>
6
+ <TMagicButton v-if="editable" class="create-code-button" type="primary" size="small" @click="createCodeBlock"
7
+ >新增</TMagicButton
8
+ >
9
+ </div>
10
+ </slot>
11
+
12
+ <!-- 代码块列表 -->
13
+ <CodeBlockList ref="codeBlockList" :custom-error="customError" @edit="editCode" @remove="deleteCode">
14
+ <template #code-block-panel-tool="{ id, data }">
15
+ <slot name="code-block-panel-tool" :id="id" :data="data"></slot>
16
+ </template>
17
+ </CodeBlockList>
18
+
19
+ <!-- 代码块编辑区 -->
20
+ <CodeBlockEditor
21
+ v-if="codeConfig"
22
+ ref="codeBlockEditor"
23
+ :disabled="!editable"
24
+ :content="codeConfig"
25
+ @submit="submitCodeBlockHandler"
26
+ ></CodeBlockEditor>
27
+ </TMagicScrollbar>
28
+ </template>
29
+
30
+ <script setup lang="ts">
31
+ import { computed, inject, ref } from 'vue';
32
+
33
+ import { TMagicButton, TMagicScrollbar } from '@tmagic/design';
34
+ import type { Id } from '@tmagic/schema';
35
+
36
+ import CodeBlockEditor from '@editor/components/CodeBlockEditor.vue';
37
+ import SearchInput from '@editor/components/SearchInput.vue';
38
+ import { useCodeBlockEdit } from '@editor/hooks/use-code-block-edit';
39
+ import type { CodeDeleteErrorType, Services } from '@editor/type';
40
+
41
+ import CodeBlockList from './CodeBlockList.vue';
42
+
43
+ defineOptions({
44
+ name: 'MEditorCodeBlockListPanel',
45
+ });
46
+
47
+ defineProps<{
48
+ customError?: (id: Id, errorType: CodeDeleteErrorType) => any;
49
+ }>();
50
+
51
+ const { codeBlockService } = inject<Services>('services') || {};
52
+
53
+ const editable = computed(() => codeBlockService?.getEditStatus());
54
+
55
+ const { codeBlockEditor, codeConfig, editCode, deleteCode, createCodeBlock, submitCodeBlockHandler } =
56
+ useCodeBlockEdit(codeBlockService);
57
+
58
+ const codeBlockList = ref<InstanceType<typeof CodeBlockList>>();
59
+
60
+ const filterTextChangeHandler = (val: string) => {
61
+ codeBlockList.value?.filter(val);
62
+ };
63
+ </script>