@tmagic/editor 1.3.5 → 1.3.7

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 (142) hide show
  1. package/LICENSE +5432 -0
  2. package/dist/style.css +88 -62
  3. package/dist/tmagic-editor.js +2448 -2016
  4. package/dist/tmagic-editor.js.map +1 -1
  5. package/dist/tmagic-editor.umd.cjs +2453 -2019
  6. package/dist/tmagic-editor.umd.cjs.map +1 -1
  7. package/package.json +23 -23
  8. package/src/Editor.vue +15 -7
  9. package/src/components/CodeBlockEditor.vue +2 -2
  10. package/src/components/ContentMenu.vue +5 -5
  11. package/src/components/FloatingBox.vue +117 -0
  12. package/src/components/ScrollBar.vue +2 -2
  13. package/src/components/ScrollViewer.vue +2 -2
  14. package/src/components/SplitView.vue +2 -2
  15. package/src/components/Tree.vue +5 -0
  16. package/src/components/TreeNode.vue +10 -4
  17. package/src/editorProps.ts +20 -3
  18. package/src/fields/PageFragmentSelect.vue +55 -0
  19. package/src/hooks/use-filter.ts +55 -0
  20. package/src/hooks/use-getso.ts +2 -2
  21. package/src/hooks/use-node-status.ts +48 -0
  22. package/src/hooks/use-stage.ts +19 -1
  23. package/src/index.ts +3 -0
  24. package/src/initService.ts +43 -17
  25. package/src/layouts/AddPageBox.vue +16 -4
  26. package/src/layouts/CodeEditor.vue +2 -2
  27. package/src/layouts/Framework.vue +17 -3
  28. package/src/layouts/PropsPanel.vue +2 -2
  29. package/src/layouts/page-bar/AddButton.vue +48 -0
  30. package/src/layouts/page-bar/PageBar.vue +158 -0
  31. package/src/layouts/{workspace → page-bar}/PageBarScrollContainer.vue +61 -35
  32. package/src/layouts/page-bar/SwitchTypeButton.vue +45 -0
  33. package/src/layouts/sidebar/Sidebar.vue +9 -2
  34. package/src/layouts/sidebar/code-block/CodeBlockList.vue +55 -65
  35. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +2 -1
  36. package/src/layouts/sidebar/data-source/DataSourceList.vue +63 -59
  37. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +1 -1
  38. package/src/layouts/sidebar/layer/LayerMenu.vue +39 -27
  39. package/src/layouts/sidebar/layer/LayerPanel.vue +31 -8
  40. package/src/layouts/sidebar/layer/use-click.ts +5 -3
  41. package/src/layouts/sidebar/layer/use-keybinding.ts +8 -8
  42. package/src/layouts/sidebar/layer/use-node-status.ts +10 -13
  43. package/src/layouts/workspace/Workspace.vue +6 -7
  44. package/src/layouts/workspace/viewer/NodeListMenu.vue +68 -129
  45. package/src/layouts/workspace/viewer/Stage.vue +14 -6
  46. package/src/layouts/workspace/viewer/ViewerMenu.vue +94 -86
  47. package/src/services/BaseService.ts +63 -26
  48. package/src/services/codeBlock.ts +7 -1
  49. package/src/services/dep.ts +12 -8
  50. package/src/services/editor.ts +131 -64
  51. package/src/services/history.ts +6 -2
  52. package/src/services/keybinding.ts +48 -13
  53. package/src/services/props.ts +70 -12
  54. package/src/services/storage.ts +23 -13
  55. package/src/services/ui.ts +4 -1
  56. package/src/theme/code-block.scss +0 -16
  57. package/src/theme/floating-box.scss +30 -0
  58. package/src/theme/layer-panel.scss +19 -0
  59. package/src/theme/page-bar.scss +18 -1
  60. package/src/theme/stage.scss +24 -0
  61. package/src/theme/theme.scss +1 -1
  62. package/src/theme/tree.scss +12 -1
  63. package/src/type.ts +28 -10
  64. package/src/utils/compose.ts +25 -6
  65. package/src/utils/content-menu.ts +6 -7
  66. package/src/utils/editor.ts +34 -18
  67. package/src/utils/operator.ts +5 -6
  68. package/types/components/CodeBlockEditor.vue.d.ts +6 -2
  69. package/types/components/CodeParams.vue.d.ts +3 -1
  70. package/types/components/ContentMenu.vue.d.ts +13 -5
  71. package/types/components/FloatingBox.vue.d.ts +78 -0
  72. package/types/components/Resizer.vue.d.ts +6 -1
  73. package/types/components/ScrollBar.vue.d.ts +3 -1
  74. package/types/components/ScrollViewer.vue.d.ts +3 -3
  75. package/types/components/SearchInput.vue.d.ts +3 -1
  76. package/types/components/SplitView.vue.d.ts +8 -4
  77. package/types/components/ToolButton.vue.d.ts +3 -3
  78. package/types/components/Tree.vue.d.ts +27 -8
  79. package/types/components/TreeNode.vue.d.ts +24 -7
  80. package/types/editorProps.d.ts +16 -1
  81. package/types/fields/Code.vue.d.ts +6 -2
  82. package/types/fields/CodeLink.vue.d.ts +5 -3
  83. package/types/fields/CodeSelect.vue.d.ts +3 -1
  84. package/types/fields/CodeSelectCol.vue.d.ts +3 -1
  85. package/types/fields/DataSourceFieldSelect.vue.d.ts +3 -1
  86. package/types/fields/DataSourceFields.vue.d.ts +5 -3
  87. package/types/fields/DataSourceInput.vue.d.ts +8 -4
  88. package/types/fields/DataSourceMethodSelect.vue.d.ts +3 -1
  89. package/types/fields/DataSourceMethods.vue.d.ts +5 -3
  90. package/types/fields/DataSourceMocks.vue.d.ts +5 -3
  91. package/types/fields/DataSourceSelect.vue.d.ts +5 -3
  92. package/types/fields/EventSelect.vue.d.ts +3 -1
  93. package/types/fields/KeyValue.vue.d.ts +2 -2
  94. package/types/fields/PageFragmentSelect.vue.d.ts +31 -0
  95. package/types/fields/UISelect.vue.d.ts +3 -1
  96. package/types/hooks/use-code-block-edit.d.ts +14 -5
  97. package/types/hooks/use-data-source-method.d.ts +14 -5
  98. package/types/hooks/use-filter.d.ts +7 -0
  99. package/types/hooks/use-node-status.d.ts +6 -0
  100. package/types/index.d.ts +1 -0
  101. package/types/layouts/AddPageBox.vue.d.ts +14 -1
  102. package/types/layouts/CodeEditor.vue.d.ts +4 -1
  103. package/types/layouts/Framework.vue.d.ts +14 -1
  104. package/types/layouts/PropsPanel.vue.d.ts +19 -13
  105. package/types/layouts/{workspace/viewer/NodeListMenuTitle.vue.d.ts → page-bar/AddButton.vue.d.ts} +3 -2
  106. package/types/layouts/page-bar/PageBar.vue.d.ts +28 -0
  107. package/types/layouts/page-bar/PageBarScrollContainer.vue.d.ts +24 -0
  108. package/types/layouts/page-bar/SwitchTypeButton.vue.d.ts +20 -0
  109. package/types/layouts/sidebar/ComponentListPanel.vue.d.ts +1 -1
  110. package/types/layouts/sidebar/Sidebar.vue.d.ts +7 -5
  111. package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +9 -3
  112. package/types/layouts/sidebar/code-block/CodeBlockListPanel.vue.d.ts +1 -1
  113. package/types/layouts/sidebar/data-source/DataSourceConfigPanel.vue.d.ts +3 -1
  114. package/types/layouts/sidebar/data-source/DataSourceList.vue.d.ts +8 -2
  115. package/types/layouts/sidebar/data-source/DataSourceListPanel.vue.d.ts +1 -1
  116. package/types/layouts/sidebar/layer/LayerMenu.vue.d.ts +26 -3
  117. package/types/layouts/sidebar/layer/LayerPanel.vue.d.ts +3 -1
  118. package/types/layouts/sidebar/layer/use-click.d.ts +37 -6
  119. package/types/layouts/sidebar/layer/use-keybinding.d.ts +1 -1
  120. package/types/layouts/sidebar/layer/use-node-status.d.ts +3 -4
  121. package/types/layouts/workspace/Workspace.vue.d.ts +3 -1
  122. package/types/layouts/workspace/viewer/NodeListMenu.vue.d.ts +1 -14
  123. package/types/layouts/workspace/viewer/Stage.vue.d.ts +2 -0
  124. package/types/layouts/workspace/viewer/ViewerMenu.vue.d.ts +9 -1
  125. package/types/services/BaseService.d.ts +4 -1
  126. package/types/services/dataSource.d.ts +1 -0
  127. package/types/services/dep.d.ts +6 -5
  128. package/types/services/editor.d.ts +12 -5
  129. package/types/services/history.d.ts +3 -2
  130. package/types/services/keybinding.d.ts +21 -1
  131. package/types/services/props.d.ts +25 -1
  132. package/types/services/storage.d.ts +7 -7
  133. package/types/type.d.ts +32 -17
  134. package/types/utils/compose.d.ts +1 -1
  135. package/types/utils/editor.d.ts +14 -8
  136. package/src/layouts/sidebar/layer/use-filter.ts +0 -59
  137. package/src/layouts/workspace/PageBar.vue +0 -87
  138. package/src/layouts/workspace/viewer/NodeListMenuTitle.vue +0 -68
  139. package/src/theme/dep-list.scss +0 -59
  140. package/types/layouts/sidebar/layer/use-filter.d.ts +0 -7
  141. package/types/layouts/workspace/PageBar.vue.d.ts +0 -15
  142. package/types/layouts/workspace/PageBarScrollContainer.vue.d.ts +0 -9
@@ -1,25 +1,20 @@
1
1
  <template>
2
2
  <div class="m-editor-page-bar" ref="pageBar">
3
- <div
4
- v-if="showAddPageButton"
5
- id="m-editor-page-bar-add-icon"
6
- class="m-editor-page-bar-item m-editor-page-bar-item-icon"
7
- @click="addPage"
8
- >
9
- <Icon :icon="Plus"></Icon>
10
- </div>
11
- <div v-else style="width: 21px"></div>
3
+ <slot name="prepend"></slot>
4
+
12
5
  <div v-if="canScroll" class="m-editor-page-bar-item m-editor-page-bar-item-icon" @click="scroll('left')">
13
6
  <Icon :icon="ArrowLeftBold"></Icon>
14
7
  </div>
8
+
15
9
  <div
16
- v-if="pageLength"
10
+ v-if="(type === NodeType.PAGE && pageLength) || (type === NodeType.PAGE_FRAGMENT && pageFragmentLength)"
17
11
  class="m-editor-page-bar-items"
18
12
  ref="itemsContainer"
19
13
  :style="`width: ${itemsContainerWidth}px`"
20
14
  >
21
15
  <slot></slot>
22
16
  </div>
17
+
23
18
  <div v-if="canScroll" class="m-editor-page-bar-item m-editor-page-bar-item-icon" @click="scroll('right')">
24
19
  <Icon :icon="ArrowRightBold"></Icon>
25
20
  </div>
@@ -27,19 +22,32 @@
27
22
  </template>
28
23
 
29
24
  <script setup lang="ts">
30
- import { computed, inject, nextTick, onMounted, onUnmounted, ref, toRaw, watch } from 'vue';
31
- import { ArrowLeftBold, ArrowRightBold, Plus } from '@element-plus/icons-vue';
25
+ import {
26
+ computed,
27
+ type ComputedRef,
28
+ inject,
29
+ nextTick,
30
+ onBeforeUnmount,
31
+ onMounted,
32
+ ref,
33
+ watch,
34
+ type WatchStopHandle,
35
+ } from 'vue';
36
+ import { ArrowLeftBold, ArrowRightBold } from '@element-plus/icons-vue';
32
37
 
33
38
  import { NodeType } from '@tmagic/schema';
34
39
 
35
40
  import Icon from '@editor/components/Icon.vue';
36
41
  import type { Services } from '@editor/type';
37
- import { generatePageNameByApp } from '@editor/utils/editor';
38
42
 
39
43
  defineOptions({
40
44
  name: 'MEditorPageBarScrollContainer',
41
45
  });
42
46
 
47
+ const props = defineProps<{
48
+ type: NodeType.PAGE | NodeType.PAGE_FRAGMENT;
49
+ }>();
50
+
43
51
  const services = inject<Services>('services');
44
52
  const editorService = services?.editorService;
45
53
  const uiService = services?.uiService;
@@ -72,7 +80,7 @@ onMounted(() => {
72
80
  pageBar.value && resizeObserver.observe(pageBar.value);
73
81
  });
74
82
 
75
- onUnmounted(() => {
83
+ onBeforeUnmount(() => {
76
84
  resizeObserver.disconnect();
77
85
  });
78
86
 
@@ -104,27 +112,45 @@ const scroll = (type: 'left' | 'right' | 'start' | 'end') => {
104
112
  itemsContainer.value.style.transform = `translate(${translateLeft}px, 0px)`;
105
113
  };
106
114
 
107
- const pageLength = computed(() => editorService?.get('pageLength'));
108
-
109
- watch(pageLength, (length = 0, preLength = 0) => {
110
- setTimeout(() => {
111
- setCanScroll();
112
- if (length < preLength) {
113
- scroll('start');
115
+ const pageLength = computed(() => editorService?.get('pageLength') || 0);
116
+ const pageFragmentLength = computed(() => editorService?.get('pageFragmentLength') || 0);
117
+
118
+ const crateWatchLength = (length: ComputedRef<number>) =>
119
+ watch(
120
+ length,
121
+ (length = 0, preLength = 0) => {
122
+ setTimeout(() => {
123
+ setCanScroll();
124
+ if (length < preLength) {
125
+ scroll('start');
126
+ } else {
127
+ scroll('end');
128
+ }
129
+ });
130
+ },
131
+ {
132
+ immediate: true,
133
+ },
134
+ );
135
+
136
+ let unWatchPageLength: WatchStopHandle | null;
137
+ let unWatchPageFragmentLength: WatchStopHandle | null;
138
+
139
+ watch(
140
+ () => props.type,
141
+ (type) => {
142
+ if (type === NodeType.PAGE) {
143
+ unWatchPageFragmentLength?.();
144
+ unWatchPageFragmentLength = null;
145
+ unWatchPageLength = crateWatchLength(pageLength);
114
146
  } else {
115
- scroll('end');
147
+ unWatchPageLength?.();
148
+ unWatchPageLength = null;
149
+ unWatchPageFragmentLength = crateWatchLength(pageFragmentLength);
116
150
  }
117
- });
118
- });
119
-
120
- const addPage = () => {
121
- if (!editorService) return;
122
- const root = toRaw(editorService.get('root'));
123
- if (!root) throw new Error('root 不能为空');
124
- const pageConfig = {
125
- type: NodeType.PAGE,
126
- name: generatePageNameByApp(root),
127
- };
128
- editorService.add(pageConfig);
129
- };
151
+ },
152
+ {
153
+ immediate: true,
154
+ },
155
+ );
130
156
  </script>
@@ -0,0 +1,45 @@
1
+ <template>
2
+ <TMagicButton
3
+ v-for="item in data"
4
+ class="m-editor-page-bar-switch-type-button"
5
+ size="small"
6
+ :key="item.type"
7
+ text
8
+ :class="{ active: modelValue === item.type }"
9
+ :type="modelValue === item.type ? 'primary' : ''"
10
+ @click="clickHandler(item.type)"
11
+ >{{ item.text }}</TMagicButton
12
+ >
13
+ </template>
14
+
15
+ <script setup lang="ts">
16
+ import { TMagicButton } from '@tmagic/design';
17
+ import { NodeType } from '@tmagic/schema';
18
+
19
+ defineOptions({
20
+ name: 'MEditorPageBarSwitchTypeButton',
21
+ });
22
+
23
+ defineProps<{
24
+ modelValue: NodeType.PAGE | NodeType.PAGE_FRAGMENT;
25
+ }>();
26
+
27
+ const data: { type: NodeType.PAGE | NodeType.PAGE_FRAGMENT; text: string }[] = [
28
+ {
29
+ type: NodeType.PAGE,
30
+ text: '页面',
31
+ },
32
+ {
33
+ type: NodeType.PAGE_FRAGMENT,
34
+ text: '页面片',
35
+ },
36
+ ];
37
+
38
+ const emit = defineEmits<{
39
+ 'update:modelValue': [value: NodeType.PAGE | NodeType.PAGE_FRAGMENT];
40
+ }>();
41
+
42
+ const clickHandler = (value: NodeType.PAGE | NodeType.PAGE_FRAGMENT) => {
43
+ emit('update:modelValue', value);
44
+ };
45
+ </script>
@@ -4,13 +4,13 @@
4
4
  <div
5
5
  class="m-editor-sidebar-header-item"
6
6
  v-for="(config, index) in sideBarItems"
7
+ v-show="!floatBoxStates?.get(config.$key)?.status"
8
+ draggable="true"
7
9
  :key="config.$key ?? index"
8
10
  :class="{ 'is-active': activeTabName === config.text }"
9
11
  @click="activeTabName = config.text || `${index}`"
10
- draggable="true"
11
12
  @dragstart="dragstartHandler"
12
13
  @dragend="dragendHandler(config.$key, $event)"
13
- v-show="!floatBoxStates?.get(config.$key)?.status"
14
14
  >
15
15
  <MIcon v-if="config.icon" :icon="config.icon"></MIcon>
16
16
  <div v-if="config.text" class="magic-editor-tab-panel-title">{{ config.text }}</div>
@@ -74,6 +74,11 @@
74
74
  <component v-else-if="config.slots?.layerNodeContent" :is="config.slots.layerNodeContent" :data="nodeData" />
75
75
  </template>
76
76
 
77
+ <template #layer-node-label="{ data: nodeData }" v-if="config.$key === 'layer' || config.slots?.layerNodeLabel">
78
+ <slot v-if="config.$key === 'layer'" name="layer-node-label" :data="nodeData"></slot>
79
+ <component v-else-if="config.slots?.layerNodeLabel" :is="config.slots.layerNodeTool" :data="nodeData" />
80
+ </template>
81
+
77
82
  <template #layer-node-tool="{ data: nodeData }" v-if="config.$key === 'layer' || config.slots?.layerNodeTool">
78
83
  <slot v-if="config.$key === 'layer'" name="layer-node-tool" :data="nodeData"></slot>
79
84
  <component v-else-if="config.slots?.layerNodeTool" :is="config.slots.layerNodeTool" :data="nodeData" />
@@ -155,6 +160,7 @@ const props = withDefaults(
155
160
  defineProps<{
156
161
  data: SideBarData;
157
162
  layerContentMenu: (MenuButton | MenuComponent)[];
163
+ customContentMenu?: (menus: (MenuButton | MenuComponent)[], type: string) => (MenuButton | MenuComponent)[];
158
164
  }>(),
159
165
  {
160
166
  data: () => ({ type: 'tabs', status: '组件', items: ['component-list', 'layer', 'code-block', 'data-source'] }),
@@ -182,6 +188,7 @@ const getItemConfig = (data: SideItem): SideComponent => {
182
188
  text: '已选组件',
183
189
  props: {
184
190
  layerContentMenu: props.layerContentMenu,
191
+ customContentMenu: props.customContentMenu,
185
192
  },
186
193
  component: LayerPanel,
187
194
  slots: {},
@@ -1,57 +1,42 @@
1
1
  <template>
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>
36
- </div>
37
- </div>
2
+ <Tree :data="codeList" :node-status-map="nodeStatusMap" @node-click="clickHandler">
3
+ <template #tree-node-label="{ data }">
4
+ <div
5
+ :class="{
6
+ code: data.type === 'code',
7
+ hook: data.type === 'key',
8
+ disabled: data.type === 'key' || data.type === 'code',
9
+ }"
10
+ >
11
+ {{ data.name }} {{ data.key ? `(${data.key})` : '' }}
38
12
  </div>
39
13
  </template>
40
- </TMagicTree>
14
+
15
+ <template #tree-node-tool="{ data }">
16
+ <TMagicTooltip v-if="data.type === 'code'" effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
17
+ <Icon :icon="editable ? Edit : View" class="edit-icon" @click.stop="editCode(`${data.key}`)"></Icon>
18
+ </TMagicTooltip>
19
+ <TMagicTooltip v-if="data.type === 'code' && editable" effect="dark" content="删除" placement="bottom">
20
+ <Icon :icon="Close" class="edit-icon" @click.stop="deleteCode(`${data.key}`)"></Icon>
21
+ </TMagicTooltip>
22
+ <slot name="code-block-panel-tool" :id="data.key" :data="data"></slot>
23
+ </template>
24
+ </Tree>
41
25
  </template>
42
26
 
43
27
  <script lang="ts" setup>
44
- import { computed, inject, ref } from 'vue';
28
+ import { computed, inject } from 'vue';
45
29
  import { Close, Edit, View } from '@element-plus/icons-vue';
46
30
 
47
31
  import { DepTargetType } from '@tmagic/dep';
48
- import { tMagicMessage, tMagicMessageBox, TMagicTooltip, TMagicTree } from '@tmagic/design';
49
- import type { Id } from '@tmagic/schema';
32
+ import { tMagicMessage, tMagicMessageBox, TMagicTooltip } from '@tmagic/design';
33
+ import type { Id, MNode } from '@tmagic/schema';
50
34
 
51
35
  import Icon from '@editor/components/Icon.vue';
52
- import AppManageIcon from '@editor/icons/AppManageIcon.vue';
53
- import CodeIcon from '@editor/icons/CodeIcon.vue';
54
- import { type CodeBlockListSlots, CodeDeleteErrorType, type CodeDslItem, type Services } from '@editor/type';
36
+ import Tree from '@editor/components/Tree.vue';
37
+ import { useFilter } from '@editor/hooks/use-filter';
38
+ import { useNodeStatus } from '@editor/hooks/use-node-status';
39
+ import { type CodeBlockListSlots, CodeDeleteErrorType, type Services, type TreeNodeData } from '@editor/type';
55
40
 
56
41
  defineSlots<CodeBlockListSlots>();
57
42
 
@@ -68,38 +53,49 @@ const emit = defineEmits<{
68
53
  remove: [id: string];
69
54
  }>();
70
55
 
71
- const { codeBlockService, depService, editorService } = inject<Services>('services') || {};
56
+ const services = inject<Services>('services');
57
+ const { codeBlockService, depService, editorService } = services || {};
72
58
 
73
59
  // 代码块列表
74
- const codeList = computed(() =>
60
+ const codeList = computed<TreeNodeData[]>(() =>
75
61
  Object.values(depService?.getTargets(DepTargetType.CODE_BLOCK) || {}).map((target) => {
76
62
  // 组件节点
77
- const compNodes = Object.entries(target.deps).map(([id, dep]) => ({
63
+ const compNodes: TreeNodeData[] = Object.entries(target.deps).map(([id, dep]) => ({
78
64
  name: dep.name,
79
65
  type: 'node',
80
- id,
81
- children: dep.keys.map((key) => ({ name: key, id: key, type: 'key' })),
66
+ id: `${target.id}_${id}`,
67
+ key: id,
68
+ items: dep.keys.map((key) => {
69
+ const data: TreeNodeData = { name: `${key}`, id: `${target.id}_${id}_${key}`, type: 'key' };
70
+ return data;
71
+ }),
82
72
  }));
83
- return {
73
+
74
+ const data: TreeNodeData = {
84
75
  id: target.id,
76
+ key: target.id,
85
77
  name: target.name,
86
78
  type: 'code',
87
79
  codeBlockContent: codeBlockService?.getCodeContentById(target.id),
88
- children: compNodes,
80
+ items: compNodes,
89
81
  };
82
+
83
+ return data;
90
84
  }),
91
85
  );
92
- // 默认展开组件层级的节点
93
- const expandedKeys = computed(() => codeList.value.map((item) => item.id));
94
- const editable = computed(() => codeBlockService?.getEditStatus());
95
86
 
96
- const filterNode = (value: string, data: CodeDslItem): boolean => {
87
+ const filterNode = (value: string, data: MNode): boolean => {
97
88
  if (!value) {
98
89
  return true;
99
90
  }
100
- return `${data.name}${data.id}`.toLocaleLowerCase().indexOf(value.toLocaleLowerCase()) !== -1;
91
+ return `${data.name}${data.id}`.toLocaleLowerCase().includes(value.toLocaleLowerCase());
101
92
  };
102
93
 
94
+ const { nodeStatusMap } = useNodeStatus(codeList);
95
+ const { filterTextChangeHandler } = useFilter(codeList, nodeStatusMap, filterNode);
96
+
97
+ const editable = computed(() => codeBlockService?.getEditStatus());
98
+
103
99
  // 选中组件
104
100
  const selectComp = (compId: Id) => {
105
101
  const stage = editorService?.get('stage');
@@ -107,11 +103,9 @@ const selectComp = (compId: Id) => {
107
103
  stage?.select(compId);
108
104
  };
109
105
 
110
- const clickHandler = (data: any, node: any) => {
106
+ const clickHandler = (event: MouseEvent, data: any) => {
111
107
  if (data.type === 'node') {
112
- selectComp(data.id);
113
- } else if (data.type === 'key') {
114
- selectComp(node.parent.data.id);
108
+ selectComp(data.key);
115
109
  }
116
110
  };
117
111
 
@@ -122,7 +116,7 @@ const editCode = (id: string) => {
122
116
 
123
117
  const deleteCode = async (id: string) => {
124
118
  const currentCode = codeList.value.find((codeItem) => codeItem.id === id);
125
- const existBinds = Boolean(currentCode?.children.length);
119
+ const existBinds = Boolean(currentCode?.items?.length);
126
120
  const undeleteableList = codeBlockService?.getUndeletableList() || [];
127
121
  if (!existBinds && !undeleteableList.includes(id)) {
128
122
  await tMagicMessageBox.confirm('确定删除该代码块吗?', '提示', {
@@ -142,11 +136,7 @@ const deleteCode = async (id: string) => {
142
136
  }
143
137
  };
144
138
 
145
- const tree = ref<InstanceType<typeof TMagicTree>>();
146
-
147
139
  defineExpose({
148
- filter(val: string) {
149
- tree.value?.filter(val);
150
- },
140
+ filter: filterTextChangeHandler,
151
141
  });
152
142
  </script>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <TMagicScrollbar class="m-editor-code-block-list m-editor-dep-list-panel">
2
+ <TMagicScrollbar class="m-editor-code-block-list m-editor-layer-panel">
3
3
  <slot name="code-block-panel-header">
4
4
  <div class="search-wrapper">
5
5
  <SearchInput @search="filterTextChangeHandler"></SearchInput>
@@ -17,6 +17,7 @@
17
17
  </template>
18
18
  </CodeBlockList>
19
19
  </TMagicScrollbar>
20
+
20
21
  <!-- 代码块编辑区 -->
21
22
  <CodeBlockEditor
22
23
  v-if="codeConfig"
@@ -1,48 +1,40 @@
1
1
  <template>
2
- <TMagicTree
3
- ref="tree"
4
- class="magic-editor-layer-tree"
5
- node-key="id"
6
- empty-text="暂无代码块"
7
- default-expand-all
8
- :expand-on-click-node="false"
9
- :data="list"
10
- :highlight-current="true"
11
- @node-click="clickHandler"
12
- >
13
- <template #default="{ data }">
14
- <div :id="data.id" class="list-container">
15
- <div class="list-item">
16
- <Icon v-if="data.type === 'code'" class="codeIcon" :icon="Coin"></Icon>
17
- <Icon v-if="data.type === 'node'" class="compIcon" :icon="Aim"></Icon>
18
- <span class="name" :class="{ code: data.type === 'ds', hook: data.type === 'key' }">{{
19
- data.type === 'key' ? data.name : `${data.name}(${data.id})`
20
- }}</span>
21
- <!-- 右侧工具栏 -->
22
- <div class="right-tool" v-if="data.type === 'ds'">
23
- <TMagicTooltip effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
24
- <Icon :icon="editable ? Edit : View" class="edit-icon" @click.stop="editHandler(`${data.id}`)"></Icon>
25
- </TMagicTooltip>
26
- <TMagicTooltip v-if="editable" effect="dark" content="删除" placement="bottom">
27
- <Icon :icon="Close" class="edit-icon" @click.stop="removeHandler(`${data.id}`)"></Icon>
28
- </TMagicTooltip>
29
- <slot name="data-source-panel-tool" :data="data"></slot>
30
- </div>
31
- </div>
2
+ <Tree :data="list" :node-status-map="nodeStatusMap" @node-click="clickHandler">
3
+ <template #tree-node-label="{ data }">
4
+ <div
5
+ :class="{
6
+ ds: data.type === 'ds',
7
+ hook: data.type === 'key',
8
+ disabled: data.type === 'key' || data.type === 'ds',
9
+ }"
10
+ >
11
+ {{ data.name }} {{ data.key ? `(${data.key})` : '' }}
32
12
  </div>
33
13
  </template>
34
- </TMagicTree>
14
+ <template #tree-node-tool="{ data }">
15
+ <TMagicTooltip v-if="data.type === 'ds'" effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
16
+ <Icon :icon="editable ? Edit : View" class="edit-icon" @click.stop="editHandler(`${data.key}`)"></Icon>
17
+ </TMagicTooltip>
18
+ <TMagicTooltip v-if="data.type === 'ds' && editable" effect="dark" content="删除" placement="bottom">
19
+ <Icon :icon="Close" class="edit-icon" @click.stop="removeHandler(`${data.key}`)"></Icon>
20
+ </TMagicTooltip>
21
+ <slot name="data-source-panel-tool" :data="data"></slot>
22
+ </template>
23
+ </Tree>
35
24
  </template>
36
25
 
37
26
  <script lang="ts" setup>
38
- import { computed, inject, ref } from 'vue';
39
- import { Aim, Close, Coin, Edit, View } from '@element-plus/icons-vue';
27
+ import { computed, inject } from 'vue';
28
+ import { Close, Edit, View } from '@element-plus/icons-vue';
40
29
 
41
30
  import { DepTargetType } from '@tmagic/dep';
42
- import { tMagicMessageBox, TMagicTooltip, TMagicTree } from '@tmagic/design';
43
- import { DepData, Id } from '@tmagic/schema';
31
+ import { tMagicMessageBox, TMagicTooltip } from '@tmagic/design';
32
+ import { DepData, Id, MNode } from '@tmagic/schema';
44
33
 
45
34
  import Icon from '@editor/components/Icon.vue';
35
+ import Tree from '@editor/components/Tree.vue';
36
+ import { useFilter } from '@editor/hooks/use-filter';
37
+ import { useNodeStatus } from '@editor/hooks/use-node-status';
46
38
  import type { DataSourceListSlots, Services } from '@editor/type';
47
39
 
48
40
  defineSlots<DataSourceListSlots>();
@@ -66,32 +58,39 @@ const dsDep = computed(() => depService?.getTargets(DepTargetType.DATA_SOURCE) |
66
58
  const dsMethodDep = computed(() => depService?.getTargets(DepTargetType.DATA_SOURCE_METHOD) || {});
67
59
  const dsCondDep = computed(() => depService?.getTargets(DepTargetType.DATA_SOURCE_COND) || {});
68
60
 
69
- const getKeyTreeConfig = (dep: DepData[string], type?: string) =>
70
- dep.keys.map((key) => ({ name: key, id: key, type: 'key', isMethod: type === 'method', isCond: type === 'cond' }));
61
+ const getKeyTreeConfig = (dep: DepData[string], type?: string, parentKey?: Id) =>
62
+ dep.keys.map((key) => ({
63
+ name: key,
64
+ id: `${parentKey}_${key}`,
65
+ type: 'key',
66
+ isMethod: type === 'method',
67
+ isCond: type === 'cond',
68
+ }));
71
69
 
72
- const getNodeTreeConfig = (id: string, dep: DepData[string], type?: string) => ({
70
+ const getNodeTreeConfig = (id: string, dep: DepData[string], type?: string, parentKey?: Id) => ({
73
71
  name: dep.name,
74
72
  type: 'node',
75
- id,
76
- children: getKeyTreeConfig(dep, type),
73
+ id: `${parentKey}_${id}`,
74
+ key: id,
75
+ items: getKeyTreeConfig(dep, type, `${parentKey}_${id}`),
77
76
  });
78
77
 
79
78
  /**
80
79
  * 生成tree中依赖节点的数据
81
- * @param children 节点
80
+ * @param items 节点
82
81
  * @param deps 依赖
83
82
  * @param type 依赖类型
84
83
  */
85
- const mergeChildren = (children: any[], deps: DepData, type?: string) => {
84
+ const mergeChildren = (dsId: Id, items: any[], deps: DepData, type?: string) => {
86
85
  Object.entries(deps).forEach(([id, dep]) => {
87
86
  // 已经生成过的节点
88
- const nodeItem = children.find((item) => item.id === id);
87
+ const nodeItem = items.find((item) => item.key === id);
89
88
  // 节点存在,则追加依赖的key
90
89
  if (nodeItem) {
91
- nodeItem.children = nodeItem.children.concat(getKeyTreeConfig(dep, type));
90
+ nodeItem.items = nodeItem.items.concat(getKeyTreeConfig(dep, type, nodeItem.key));
92
91
  } else {
93
92
  // 节点不存在,则生成
94
- children.push(getNodeTreeConfig(id, dep, type));
93
+ items.push(getNodeTreeConfig(id, dep, type, dsId));
95
94
  }
96
95
  });
97
96
  };
@@ -102,21 +101,32 @@ const list = computed(() =>
102
101
  const dsMethodDeps = dsMethodDep.value[ds.id]?.deps || {};
103
102
  const dsCondDeps = dsCondDep.value[ds.id]?.deps || {};
104
103
 
105
- const children: any[] = [];
104
+ const items: any[] = [];
106
105
  // 数据源依赖分为三种类型:key/node、method、cond,是分开存储,这里将其合并展示
107
- mergeChildren(children, dsDeps);
108
- mergeChildren(children, dsMethodDeps, 'method');
109
- mergeChildren(children, dsCondDeps, 'cond');
106
+ mergeChildren(ds.id, items, dsDeps);
107
+ mergeChildren(ds.id, items, dsMethodDeps, 'method');
108
+ mergeChildren(ds.id, items, dsCondDeps, 'cond');
110
109
 
111
110
  return {
112
111
  id: ds.id,
112
+ key: ds.id,
113
113
  name: ds.title,
114
114
  type: 'ds',
115
- children,
115
+ items,
116
116
  };
117
117
  }),
118
118
  );
119
119
 
120
+ const filterNode = (value: string, data: MNode): boolean => {
121
+ if (!value) {
122
+ return true;
123
+ }
124
+ return `${data.name}${data.id}`.toLocaleLowerCase().includes(value.toLocaleLowerCase());
125
+ };
126
+
127
+ const { nodeStatusMap } = useNodeStatus(list);
128
+ const { filterTextChangeHandler } = useFilter(list, nodeStatusMap, filterNode);
129
+
120
130
  const editHandler = (id: string) => {
121
131
  emit('edit', id);
122
132
  };
@@ -138,19 +148,13 @@ const selectComp = (compId: Id) => {
138
148
  stage?.select(compId);
139
149
  };
140
150
 
141
- const clickHandler = (data: any, node: any) => {
151
+ const clickHandler = (event: MouseEvent, data: any) => {
142
152
  if (data.type === 'node') {
143
- selectComp(data.id);
144
- } else if (data.type === 'key') {
145
- selectComp(node.parent.data.id);
153
+ selectComp(data.key);
146
154
  }
147
155
  };
148
156
 
149
- const tree = ref<InstanceType<typeof TMagicTree>>();
150
-
151
157
  defineExpose({
152
- filter(val: string) {
153
- tree.value?.filter(val);
154
- },
158
+ filter: filterTextChangeHandler,
155
159
  });
156
160
  </script>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <TMagicScrollbar class="data-source-list-panel m-editor-dep-list-panel">
2
+ <TMagicScrollbar class="data-source-list-panel m-editor-layer-panel">
3
3
  <div class="search-wrapper">
4
4
  <SearchInput @search="filterTextChangeHandler"></SearchInput>
5
5
  <TMagicPopover v-if="editable" placement="right">