@tmagic/editor 1.3.0-alpha.7 → 1.3.0-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.3.0-alpha.7",
2
+ "version": "1.3.0-alpha.9",
3
3
  "name": "@tmagic/editor",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -46,27 +46,27 @@
46
46
  "dependencies": {
47
47
  "@babel/core": "^7.18.0",
48
48
  "@element-plus/icons-vue": "^2.0.9",
49
- "@tmagic/core": "1.3.0-alpha.7",
50
- "@tmagic/design": "1.3.0-alpha.7",
51
- "@tmagic/form": "1.3.0-alpha.7",
52
- "@tmagic/schema": "1.3.0-alpha.7",
53
- "@tmagic/stage": "1.3.0-alpha.7",
54
- "@tmagic/table": "1.3.0-alpha.7",
55
- "@tmagic/utils": "1.3.0-alpha.7",
49
+ "@tmagic/core": "1.3.0-alpha.9",
50
+ "@tmagic/design": "1.3.0-alpha.9",
51
+ "@tmagic/form": "1.3.0-alpha.9",
52
+ "@tmagic/schema": "1.3.0-alpha.9",
53
+ "@tmagic/stage": "1.3.0-alpha.9",
54
+ "@tmagic/table": "1.3.0-alpha.9",
55
+ "@tmagic/utils": "1.3.0-alpha.9",
56
56
  "buffer": "^6.0.3",
57
57
  "color": "^3.1.3",
58
58
  "events": "^3.3.0",
59
59
  "gesto": "^1.7.0",
60
60
  "keycon": "^1.1.2",
61
61
  "lodash-es": "^4.17.21",
62
- "monaco-editor": "^0.34.0",
62
+ "monaco-editor": "^0.39.0",
63
63
  "serialize-javascript": "^6.0.0",
64
64
  "vue": "^3.3.4"
65
65
  },
66
66
  "peerDependencies": {
67
- "@tmagic/design": "1.3.0-alpha.7",
68
- "@tmagic/form": "1.3.0-alpha.7",
69
- "monaco-editor": "^0.34.0",
67
+ "@tmagic/design": "1.3.0-alpha.9",
68
+ "@tmagic/form": "1.3.0-alpha.9",
69
+ "monaco-editor": "^0.39.0",
70
70
  "vue": "^3.3.4"
71
71
  },
72
72
  "devDependencies": {
@@ -49,7 +49,7 @@ defineOptions({
49
49
  name: 'MEditorFunctionEditor',
50
50
  });
51
51
 
52
- provide('mForm', {});
52
+ provide('mForm', null);
53
53
 
54
54
  const defaultParamColConfig: ColumnConfig = {
55
55
  type: 'row',
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div ref="el" class="m-editor-layout">
3
- <template v-if="hasLeft">
3
+ <template v-if="hasLeft && $slots.left">
4
4
  <div class="m-editor-layout-left" :class="leftClass" :style="`width: ${left}px`">
5
5
  <slot name="left"></slot>
6
6
  </div>
@@ -11,7 +11,7 @@
11
11
  <slot name="center"></slot>
12
12
  </div>
13
13
 
14
- <template v-if="hasRight">
14
+ <template v-if="hasRight && $slots.right">
15
15
  <Resizer @change="changeRight"></Resizer>
16
16
  <div class="m-editor-layout-right" :class="rightClass" :style="`width: ${right}px`">
17
17
  <slot name="right"></slot>
@@ -30,13 +30,15 @@
30
30
  </div>
31
31
  </template>
32
32
  </component>
33
- <div :class="`el-input el-input--${size}`" @mouseup="mouseupHandler" v-else>
34
- <div :class="`el-input__wrapper ${isFocused ? ' is-focus' : ''}`">
33
+ <div :class="`tmagic-data-source-input-text el-input el-input--${size}`" @mouseup="mouseupHandler" v-else>
34
+ <div :class="`tmagic-data-source-input-text-wrapper el-input__wrapper ${isFocused ? ' is-focus' : ''}`">
35
35
  <div class="el-input__inner">
36
36
  <template v-for="(item, index) in displayState">
37
37
  <span :key="index" v-if="item.type === 'text'" style="margin-right: 2px">{{ item.value }}</span>
38
38
  <TMagicTag :key="index" :size="size" v-if="item.type === 'var'">{{ item.value }}</TMagicTag>
39
39
  </template>
40
+
41
+ <Icon class="tmagic-data-source-input-icon" :icon="Coin" />
40
42
  </div>
41
43
  </div>
42
44
  </div>
@@ -90,7 +92,7 @@ const dataSources = computed(() => dataSourceService?.get('dataSources') || []);
90
92
  const setDisplayState = () => {
91
93
  displayState.value = [];
92
94
 
93
- const matches = state.value.matchAll(/\{\{([\s\S]+?)\}\}/g);
95
+ const matches = state.value.matchAll(/\$\{([\s\S]+?)\}/g);
94
96
  let index = 0;
95
97
  for (const match of matches) {
96
98
  if (typeof match.index === 'undefined') break;
@@ -195,7 +197,7 @@ const getSelectionStart = () => {
195
197
  * @param leftCurlyBracketIndex {字符索引
196
198
  */
197
199
  const curCharIsLeftCurlyBracket = (leftCurlyBracketIndex: number) =>
198
- leftCurlyBracketIndex > -1 && leftCurlyBracketIndex === getSelectionStart() - 1;
200
+ leftCurlyBracketIndex > 0 && leftCurlyBracketIndex === getSelectionStart() - 1;
199
201
 
200
202
  /**
201
203
  * 当前输入的是.
@@ -213,7 +215,7 @@ const dsQuerySearch = (queryString: string, leftCurlyBracketIndex: number, cb: (
213
215
  if (curCharIsLeftCurlyBracket(leftCurlyBracketIndex)) {
214
216
  // 当前输入的是{
215
217
  result = dataSources.value;
216
- } else if (leftCurlyBracketIndex > -1) {
218
+ } else if (leftCurlyBracketIndex > 0) {
217
219
  // 当前输入的是{xx
218
220
  const queryName = queryString.substring(leftCurlyBracketIndex + 1).toLowerCase();
219
221
  result = dataSources.value.filter((ds) => ds.title?.toLowerCase().includes(queryName) || ds.id.includes(queryName));
@@ -299,7 +301,7 @@ const querySearch = (queryString: string, cb: (data: { value: string }[]) => voi
299
301
  const curQueryString = queryString.substring(0, selectionStart);
300
302
 
301
303
  const fieldKeyStringLastIndex = curQueryString.lastIndexOf('.');
302
- const dsKeyStringLastIndex = curQueryString.lastIndexOf('{');
304
+ const dsKeyStringLastIndex = curQueryString.lastIndexOf('${') + 1;
303
305
 
304
306
  const isFieldTip = fieldKeyStringLastIndex > dsKeyStringLastIndex;
305
307
 
@@ -321,7 +323,7 @@ const selectHandler = async ({ value, type }: { value: string; type: 'dataSource
321
323
  let startText = inputText.substring(0, selectionStart);
322
324
 
323
325
  const dotIndex = startText.lastIndexOf('.');
324
- const leftCurlyBracketIndex = startText.lastIndexOf('{');
326
+ const leftCurlyBracketIndex = startText.lastIndexOf('${') + 1;
325
327
 
326
328
  const endText = inputText.substring(selectionStart);
327
329
 
@@ -336,7 +338,6 @@ const selectHandler = async ({ value, type }: { value: string; type: 'dataSource
336
338
  if (!isRightCurlyBracket(selectionStart + 1)) {
337
339
  suggestText = `${suggestText}}`;
338
340
  }
339
- suggestText = `{${suggestText}}`;
340
341
  } else if (!curCharIsDot(dotIndex)) {
341
342
  startText = startText.substring(0, dotIndex + 1);
342
343
  }
@@ -345,10 +346,10 @@ const selectHandler = async ({ value, type }: { value: string; type: 'dataSource
345
346
 
346
347
  await nextTick();
347
348
 
348
- // 由于选择数据源时会在后面补全}}, 所以光标要前移2位
349
+ // 由于选择数据源时会在后面补全}, 所以光标要前移2位
349
350
  let newSelectionStart = 0;
350
351
  if (isDataSource) {
351
- newSelectionStart = leftCurlyBracketIndex + suggestText.length - 1;
352
+ newSelectionStart = leftCurlyBracketIndex + suggestText.length;
352
353
  } else {
353
354
  newSelectionStart = dotIndex + suggestText.length + 1;
354
355
  }
@@ -0,0 +1,75 @@
1
+ <template>
2
+ <MSelect
3
+ :model="model"
4
+ :name="name"
5
+ :size="size"
6
+ :prop="prop"
7
+ :disabled="disabled"
8
+ :config="selectConfig"
9
+ :last-values="lastValues"
10
+ @change="changeHandler"
11
+ ></MSelect>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { computed, inject } from 'vue';
16
+
17
+ import { FieldSize } from '@tmagic/design';
18
+ import { MSelect, SelectConfig } from '@tmagic/form';
19
+
20
+ import { Services } from '../type';
21
+
22
+ defineOptions({
23
+ name: 'MEditorDataSourceSelect',
24
+ });
25
+
26
+ const emit = defineEmits(['change']);
27
+
28
+ const props = withDefaults(
29
+ defineProps<{
30
+ config: {
31
+ type: 'data-source-select';
32
+ name: string;
33
+ text: string;
34
+ placeholder: string;
35
+ dataSourceType?: string;
36
+ };
37
+ model: Record<string, any>;
38
+ name: string;
39
+ prop: string;
40
+ disabled: boolean;
41
+ lastValues?: Record<string, any>;
42
+ size?: FieldSize;
43
+ }>(),
44
+ {
45
+ disabled: false,
46
+ },
47
+ );
48
+
49
+ const { dataSourceService } = inject<Services>('services') || {};
50
+
51
+ const dataSources = computed(() => dataSourceService?.get('dataSources') || []);
52
+
53
+ const selectConfig = computed<SelectConfig>(() => {
54
+ const { type, dataSourceType, ...config } = props.config;
55
+ return {
56
+ ...config,
57
+ type: 'select',
58
+ valueKey: 'dataSourceId',
59
+ options: dataSources.value
60
+ .filter((ds) => !dataSourceType || ds.type === dataSourceType)
61
+ .map((ds) => ({
62
+ value: {
63
+ isBindDataSource: true,
64
+ dataSourceType: ds.type,
65
+ dataSourceId: ds.id,
66
+ },
67
+ text: ds.title || ds.id,
68
+ })),
69
+ };
70
+ });
71
+
72
+ const changeHandler = (value: any) => {
73
+ emit('change', value);
74
+ };
75
+ </script>
package/src/index.ts CHANGED
@@ -23,6 +23,7 @@ import CodeSelect from './fields/CodeSelect.vue';
23
23
  import CodeSelectCol from './fields/CodeSelectCol.vue';
24
24
  import DataSourceFields from './fields/DataSourceFields.vue';
25
25
  import DataSourceInput from './fields/DataSourceInput.vue';
26
+ import DataSourceSelect from './fields/DataSourceSelect.vue';
26
27
  import EventSelect from './fields/EventSelect.vue';
27
28
  import KeyValue from './fields/KeyValue.vue';
28
29
  import uiSelect from './fields/UISelect.vue';
@@ -53,6 +54,7 @@ export { default as CodeSelect } from './fields/CodeSelect.vue';
53
54
  export { default as CodeSelectCol } from './fields/CodeSelectCol.vue';
54
55
  export { default as DataSourceFields } from './fields/DataSourceFields.vue';
55
56
  export { default as DataSourceInput } from './fields/DataSourceInput.vue';
57
+ export { default as DataSourceSelect } from './fields/DataSourceSelect.vue';
56
58
  export { default as EventSelect } from './fields/EventSelect.vue';
57
59
  export { default as KeyValue } from './fields/KeyValue.vue';
58
60
  export { default as CodeBlockList } from './layouts/sidebar/code-block/CodeBlockList.vue';
@@ -62,6 +64,7 @@ export { default as ContentMenu } from './components/ContentMenu.vue';
62
64
  export { default as Icon } from './components/Icon.vue';
63
65
  export { default as LayoutContainer } from './components/SplitView.vue';
64
66
  export { default as SplitView } from './components/SplitView.vue';
67
+ export { default as Resizer } from './components/Resizer.vue';
65
68
 
66
69
  const defaultInstallOpt: InstallOptions = {
67
70
  // eslint-disable-next-line no-eval
@@ -86,5 +89,6 @@ export default {
86
89
  app.component('m-fields-data-source-fields', DataSourceFields);
87
90
  app.component('m-fields-key-value', KeyValue);
88
91
  app.component('m-fields-data-source-input', DataSourceInput);
92
+ app.component('m-fields-data-source-select', DataSourceSelect);
89
93
  },
90
94
  };
@@ -236,18 +236,22 @@ export const initServiceEvents = (
236
236
  }
237
237
  };
238
238
 
239
+ // 新增节点,收集依赖
239
240
  const nodeAddHandler = (nodes: MNode[]) => {
240
241
  depService.collect(nodes);
241
242
  };
242
243
 
244
+ // 节点更新,收集依赖
243
245
  const nodeUpdateHandler = (nodes: MNode[]) => {
244
246
  depService.collect(nodes);
245
247
  };
246
248
 
249
+ // 节点删除,清除对齐的依赖收集
247
250
  const nodeRemoveHandler = (nodes: MNode[]) => {
248
251
  depService.clear(nodes);
249
252
  };
250
253
 
254
+ // 由于历史记录变化是更新整个page,所以历史记录变化时,需要重新收集依赖
251
255
  const historyChangeHandler = (page: MPage) => {
252
256
  depService.collect([page], true);
253
257
  };
@@ -37,10 +37,14 @@ const emit = defineEmits(['initd', 'save']);
37
37
  const toString = (v: string | any, language: string): string => {
38
38
  let value = '';
39
39
  if (typeof v !== 'string') {
40
- value = serialize(v, {
41
- space: 2,
42
- unsafe: true,
43
- }).replace(/"(\w+)":\s/g, '$1: ');
40
+ if (props.language.toLocaleLowerCase() === 'json') {
41
+ value = JSON.stringify(v, null, 2);
42
+ } else {
43
+ value = serialize(v, {
44
+ space: 2,
45
+ unsafe: true,
46
+ }).replace(/"(\w+)":\s/g, '$1: ');
47
+ }
44
48
  } else {
45
49
  value = v;
46
50
  }
@@ -81,7 +85,7 @@ const setEditorValue = (v: string | any, m: string | any) => {
81
85
  };
82
86
 
83
87
  const getEditorValue = () =>
84
- props.type === 'diff' ? vsDiffEditor?.getModifiedEditor().getValue() : vsEditor?.getValue();
88
+ (props.type === 'diff' ? vsDiffEditor?.getModifiedEditor().getValue() : vsEditor?.getValue()) || '';
85
89
 
86
90
  const init = async () => {
87
91
  if (!codeEditor.value) return;
@@ -109,13 +113,19 @@ const init = async () => {
109
113
  if (e.keyCode === 83 && (navigator.platform.match('Mac') ? e.metaKey : e.ctrlKey)) {
110
114
  e.preventDefault();
111
115
  e.stopPropagation();
112
- emit('save', getEditorValue());
116
+ const newValue = getEditorValue();
117
+ values.value = newValue;
118
+ emit('save', newValue);
113
119
  }
114
120
  });
115
121
 
116
122
  if (props.type !== 'diff' && props.autoSave) {
117
123
  vsEditor?.onDidBlurEditorWidget(() => {
118
- emit('save', getEditorValue());
124
+ const newValue = getEditorValue();
125
+ if (values.value !== newValue) {
126
+ values.value = newValue;
127
+ emit('save', newValue);
128
+ }
119
129
  });
120
130
  }
121
131
 
@@ -146,10 +156,20 @@ onUnmounted(() => {
146
156
  });
147
157
 
148
158
  defineExpose({
159
+ values,
160
+
149
161
  getEditor() {
150
162
  return vsEditor || vsDiffEditor;
151
163
  },
152
164
 
165
+ getVsEditor() {
166
+ return vsEditor;
167
+ },
168
+
169
+ getVsDiffEditor() {
170
+ return vsDiffEditor;
171
+ },
172
+
153
173
  setEditorValue,
154
174
 
155
175
  focus() {
@@ -33,7 +33,7 @@
33
33
  </slot>
34
34
  </template>
35
35
 
36
- <template v-if="pageLength > 0 && nodes.length === 1" #right>
36
+ <template v-if="pageLength > 0" #right>
37
37
  <TMagicScrollbar>
38
38
  <slot name="props-panel"></slot>
39
39
  </TMagicScrollbar>
@@ -68,7 +68,6 @@ const codeOptions = inject('codeOptions', {});
68
68
  const { editorService, uiService } = inject<Services>('services') || {};
69
69
 
70
70
  const root = computed(() => editorService?.get('root'));
71
- const nodes = computed(() => editorService?.get('nodes') || []);
72
71
 
73
72
  const pageLength = computed(() => editorService?.get('pageLength') || 0);
74
73
  const showSrc = computed(() => uiService?.get('showSrc'));
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="m-editor-props-panel">
2
+ <div class="m-editor-props-panel" v-if="nodes.length === 1">
3
3
  <slot name="props-panel-header"></slot>
4
4
  <MForm
5
5
  ref="configForm"
@@ -35,6 +35,7 @@ const configForm = ref<InstanceType<typeof MForm>>();
35
35
  const curFormConfig = ref<any>([]);
36
36
  const services = inject<Services>('services');
37
37
  const node = computed(() => services?.editorService.get('node'));
38
+ const nodes = computed(() => services?.editorService.get('nodes') || []);
38
39
  const propsPanelSize = computed(() => services?.uiService.get('propsPanelSize') || 'small');
39
40
  const stage = computed(() => services?.editorService.get('stage'));
40
41
 
@@ -83,14 +83,13 @@ const appendComponent = ({ text, type, data = {} }: ComponentItem): void => {
83
83
 
84
84
  const dragstartHandler = ({ text, type, data = {} }: ComponentItem, e: DragEvent) => {
85
85
  if (e.dataTransfer) {
86
- e.dataTransfer.effectAllowed = 'move';
87
86
  e.dataTransfer.setData(
88
- 'data',
87
+ 'text/html',
89
88
  serialize({
90
89
  name: text,
91
90
  type,
92
91
  ...data,
93
- }).replace(/"(\w+)":\s/g, '$1: '),
92
+ }),
94
93
  );
95
94
  }
96
95
  };
@@ -121,6 +120,6 @@ const dragHandler = (e: DragEvent) => {
121
120
 
122
121
  if (timeout || !stage.value) return;
123
122
 
124
- timeout = stage.value.getAddContainerHighlightClassNameTimeout(e);
123
+ timeout = stage.value.delayedMarkContainer(e);
125
124
  };
126
125
  </script>
@@ -22,6 +22,7 @@ const props = defineProps<{
22
22
  const services = inject<Services>('services');
23
23
  const menu = ref<InstanceType<typeof ContentMenu>>();
24
24
  const node = computed(() => services?.editorService.get('node'));
25
+ const nodes = computed(() => services?.editorService.get('nodes'));
25
26
  const isRoot = computed(() => node.value?.type === NodeType.ROOT);
26
27
  const isPage = computed(() => node.value?.type === NodeType.PAGE);
27
28
  const componentList = computed(() => services?.componentListService.getList() || []);
@@ -82,7 +83,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() => [
82
83
  type: 'button',
83
84
  text: '新增',
84
85
  icon: markRaw(Plus),
85
- display: () => node.value?.items,
86
+ display: () => node.value?.items && nodes.value?.length === 1,
86
87
  items: getSubMenuData.value,
87
88
  },
88
89
  {
@@ -91,7 +92,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() => [
91
92
  icon: markRaw(CopyDocument),
92
93
  display: () => !isRoot.value,
93
94
  handler: () => {
94
- node.value && services?.editorService.copy(node.value);
95
+ node.value && services?.editorService.copy(nodes.value || []);
95
96
  },
96
97
  },
97
98
  {
@@ -100,7 +101,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() => [
100
101
  icon: markRaw(Delete),
101
102
  display: () => !isRoot.value && !isPage.value,
102
103
  handler: () => {
103
- node.value && services?.editorService.remove(node.value);
104
+ node.value && services?.editorService.remove(nodes.value || []);
104
105
  },
105
106
  },
106
107
  ...props.layerContentMenu,
@@ -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>
@@ -35,9 +35,7 @@
35
35
  <template #default="{ node, data }">
36
36
  <div class="cus-tree-node" :id="data.id" @mouseenter="highlightHandler(data)">
37
37
  <slot name="layer-node-content" :node="node" :data="data">
38
- <span>
39
- {{ `${data.name} (${data.id})` }}
40
- </span>
38
+ <LayerNode :data="data"></LayerNode>
41
39
  </slot>
42
40
  </div>
43
41
  </template>
@@ -63,6 +61,7 @@ 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';
66
65
 
67
66
  defineOptions({
68
67
  name: 'MEditorLayerPanel',
@@ -350,7 +349,11 @@ const clickHandler = (data: MNode): void => {
350
349
  // 右键菜单
351
350
  const contextmenu = async (event: MouseEvent, data: MNode): Promise<void> => {
352
351
  event.preventDefault();
353
- await select(data);
352
+
353
+ if (nodes.value.length < 2) {
354
+ await select(data);
355
+ }
356
+
354
357
  menu.value?.show(event);
355
358
  };
356
359
  </script>
@@ -15,6 +15,7 @@
15
15
  :expand-on-click-node="false"
16
16
  :data="list"
17
17
  :highlight-current="true"
18
+ @node-click="clickHandler"
18
19
  >
19
20
  <template #default="{ data }">
20
21
  <div :id="data.id" class="list-container">
@@ -53,7 +54,7 @@ import { computed, inject, ref } from 'vue';
53
54
  import { Aim, Close, Coin, Edit } from '@element-plus/icons-vue';
54
55
 
55
56
  import { TMagicButton, tMagicMessageBox, TMagicScrollbar, TMagicTooltip, TMagicTree } from '@tmagic/design';
56
- import { DataSourceSchema } from '@tmagic/schema';
57
+ import { DataSourceSchema, Id } from '@tmagic/schema';
57
58
 
58
59
  import Icon from '@editor/components/Icon.vue';
59
60
  import SearchInput from '@editor/components/SearchInput.vue';
@@ -66,7 +67,7 @@ defineOptions({
66
67
  });
67
68
 
68
69
  const services = inject<Partial<Services>>('services', {});
69
- const { dataSourceService, depService } = inject<Services>('services') || {};
70
+ const { dataSourceService, depService, editorService } = inject<Services>('services') || {};
70
71
 
71
72
  const list = computed(() =>
72
73
  Object.values(depService?.targets['data-source'] || {}).map((target) => ({
@@ -131,4 +132,19 @@ const tree = ref<InstanceType<typeof TMagicTree>>();
131
132
  const filterTextChangeHandler = (val: string) => {
132
133
  tree.value?.filter(val);
133
134
  };
135
+
136
+ // 选中组件
137
+ const selectComp = (compId: Id) => {
138
+ const stage = editorService?.get('stage');
139
+ editorService?.select(compId);
140
+ stage?.select(compId);
141
+ };
142
+
143
+ const clickHandler = (data: any, node: any) => {
144
+ if (data.type === 'node') {
145
+ selectComp(data.id);
146
+ } else if (data.type === 'key') {
147
+ selectComp(node.parent.data.id);
148
+ }
149
+ };
134
150
  </script>
@@ -146,9 +146,8 @@ const contextmenuHandler = (e: MouseEvent) => {
146
146
 
147
147
  const dragoverHandler = (e: DragEvent) => {
148
148
  e.preventDefault();
149
- if (e.dataTransfer) {
150
- e.dataTransfer.dropEffect = 'move';
151
- }
149
+ if (!e.dataTransfer) return;
150
+ e.dataTransfer.dropEffect = 'move';
152
151
  };
153
152
 
154
153
  const dropHandler = async (e: DragEvent) => {
@@ -164,7 +163,15 @@ const dropHandler = async (e: DragEvent) => {
164
163
 
165
164
  if (e.dataTransfer && parent && stageContainer.value && stage) {
166
165
  const parseDSL = getConfig('parseDSL');
167
- const config = parseDSL(`(${e.dataTransfer.getData('data')})`);
166
+
167
+ const data = e.dataTransfer.getData('text/html');
168
+
169
+ if (!data) return;
170
+
171
+ const config = parseDSL(`(${data})`);
172
+
173
+ if (!config) return;
174
+
168
175
  const layout = await services?.editorService.getLayout(parent);
169
176
 
170
177
  const containerRect = stageContainer.value.getBoundingClientRect();
@@ -262,6 +262,7 @@ export class Watcher extends EventEmitter {
262
262
  Object.values(this.targets).forEach((targets) => {
263
263
  Object.values(targets).forEach((target) => {
264
264
  nodes.forEach((node) => {
265
+ // 先删除原有依赖,重新收集
265
266
  target.removeDep(node);
266
267
  this.collectItem(node, target, deep);
267
268
  });
@@ -0,0 +1,18 @@
1
+ .tmagic-data-source-input-text {
2
+ .el-input__wrapper.tmagic-data-source-input-text-wrapper {
3
+ overflow: hidden;
4
+ padding-right: 30px;
5
+ }
6
+
7
+ .el-input__inner {
8
+ display: flex;
9
+ align-items: center;
10
+ overflow: hidden;
11
+ white-space: nowrap;
12
+ }
13
+
14
+ .tmagic-data-source-input-icon {
15
+ position: absolute;
16
+ right: 7px;
17
+ }
18
+ }
@@ -44,6 +44,12 @@
44
44
  .magic-editor-layer-panel .cus-tree-node {
45
45
  width: 100%;
46
46
  overflow: hidden;
47
+ display: flex;
48
+ justify-content: space-between;
49
+
50
+ .layer-node-tool {
51
+ margin-right: 15px;
52
+ }
47
53
  }
48
54
 
49
55
  .magic-editor-layer-panel .cus-tree-node-hover {
@@ -19,4 +19,5 @@
19
19
  @import "./dep-list.scss";
20
20
  @import "./data-source.scss";
21
21
  @import "./data-source-fields.scss";
22
+ @import "./data-source-input.scss";
22
23
  @import "./key-value.scss";
package/src/utils/dep.ts CHANGED
@@ -11,6 +11,10 @@ export const createCodeBlockTarget = (id: Id, codeBlock: CodeBlockContent) =>
11
11
  id,
12
12
  name: codeBlock.name,
13
13
  isTarget: (key: string | number, value: any) => {
14
+ if (id === value) {
15
+ return true;
16
+ }
17
+
14
18
  if (value?.hookType === HookType.CODE && !isEmpty(value.hookData)) {
15
19
  const index = value.hookData.findIndex((item: HookData) => item.codeId === id);
16
20
  return Boolean(index > -1);
@@ -25,5 +29,7 @@ export const createDataSourceTarget = (id: Id, ds: DataSourceSchema) =>
25
29
  type: 'data-source',
26
30
  id,
27
31
  name: ds.title || `${id}`,
28
- isTarget: (key: string | number, value: any) => typeof value === 'string' && value.includes(`${id}`),
32
+ isTarget: (key: string | number, value: any) =>
33
+ // 关联数据源对象或者在模板在使用数据源
34
+ (value.isBindDataSource && value.dataSourceId) || (typeof value === 'string' && value.includes(`${id}`)),
29
35
  });