@tmagic/editor 1.3.0-alpha.16 → 1.3.0-alpha.18

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 (51) hide show
  1. package/dist/style.css +1 -1
  2. package/dist/tmagic-editor.js +933 -673
  3. package/dist/tmagic-editor.js.map +1 -1
  4. package/dist/tmagic-editor.umd.cjs +944 -678
  5. package/dist/tmagic-editor.umd.cjs.map +1 -1
  6. package/package.json +12 -12
  7. package/src/components/CodeBlockEditor.vue +1 -0
  8. package/src/fields/Code.vue +6 -10
  9. package/src/fields/CodeLink.vue +6 -7
  10. package/src/fields/CodeSelect.vue +5 -8
  11. package/src/fields/CodeSelectCol.vue +4 -15
  12. package/src/fields/DataSourceFieldSelect.vue +47 -0
  13. package/src/fields/DataSourceFields.vue +5 -10
  14. package/src/fields/DataSourceInput.vue +9 -12
  15. package/src/fields/DataSourceMethodSelect.vue +5 -16
  16. package/src/fields/DataSourceMethods.vue +6 -11
  17. package/src/fields/DataSourceSelect.vue +5 -12
  18. package/src/fields/EventSelect.vue +20 -12
  19. package/src/fields/KeyValue.vue +9 -11
  20. package/src/fields/UISelect.vue +19 -10
  21. package/src/index.ts +3 -0
  22. package/src/initService.ts +36 -16
  23. package/src/layouts/sidebar/code-block/CodeBlockList.vue +2 -2
  24. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +1 -0
  25. package/src/layouts/sidebar/data-source/DataSourceList.vue +51 -17
  26. package/src/services/dep.ts +19 -19
  27. package/src/theme/code-editor.scss +1 -1
  28. package/src/type.ts +20 -0
  29. package/src/utils/dep.ts +33 -7
  30. package/src/utils/props.ts +298 -189
  31. package/src/utils/stage.ts +3 -5
  32. package/types/fields/Code.vue.d.ts +11 -26
  33. package/types/fields/CodeLink.vue.d.ts +12 -21
  34. package/types/fields/CodeSelect.vue.d.ts +6 -17
  35. package/types/fields/CodeSelectCol.vue.d.ts +3 -18
  36. package/types/fields/DataSourceFieldSelect.vue.d.ts +29 -0
  37. package/types/fields/DataSourceFields.vue.d.ts +7 -20
  38. package/types/fields/DataSourceInput.vue.d.ts +10 -30
  39. package/types/fields/DataSourceMethodSelect.vue.d.ts +3 -18
  40. package/types/fields/DataSourceMethods.vue.d.ts +7 -20
  41. package/types/fields/DataSourceSelect.vue.d.ts +13 -29
  42. package/types/fields/EventSelect.vue.d.ts +2 -13
  43. package/types/fields/KeyValue.vue.d.ts +9 -24
  44. package/types/fields/UISelect.vue.d.ts +2 -11
  45. package/types/index.d.ts +1 -0
  46. package/types/initService.d.ts +1 -1
  47. package/types/services/dep.d.ts +12 -21
  48. package/types/services/props.d.ts +8 -113
  49. package/types/type.d.ts +18 -0
  50. package/types/utils/dep.d.ts +4 -2
  51. package/types/utils/props.d.ts +13 -102
@@ -7,9 +7,14 @@ import type { CodeBlockContent, DataSourceSchema, Id, MApp, MNode, MPage } from
7
7
  import { getNodes } from '@tmagic/utils';
8
8
 
9
9
  import type { Target } from './services/dep';
10
- import { createCodeBlockTarget, createDataSourceTarget } from './utils/dep';
10
+ import {
11
+ createCodeBlockTarget,
12
+ createDataSourceCondTarget,
13
+ createDataSourceMethodTarget,
14
+ createDataSourceTarget,
15
+ } from './utils/dep';
11
16
  import editorProps from './editorProps';
12
- import type { Services } from './type';
17
+ import { DepTargetType, Services } from './type';
13
18
 
14
19
  export declare type LooseRequired<T> = {
15
20
  [P in string & keyof T]: T[P];
@@ -139,6 +144,7 @@ export const initServiceEvents = (
139
144
 
140
145
  if (app.dsl) {
141
146
  app.dsl.dataSourceDeps = root.dataSourceDeps;
147
+ app.dsl.dataSourceCondDeps = root.dataSourceCondDeps;
142
148
  app.dsl.dataSources = root.dataSources;
143
149
  }
144
150
 
@@ -159,23 +165,34 @@ export const initServiceEvents = (
159
165
  };
160
166
 
161
167
  const targetAddHandler = (target: Target) => {
162
- if (target.type !== 'data-source') return;
163
-
164
168
  const root = editorService.get('root');
165
169
  if (!root) return;
166
170
 
167
- if (!root.dataSourceDeps) {
168
- root.dataSourceDeps = {};
171
+ if (target.type === DepTargetType.DATA_SOURCE) {
172
+ if (!root.dataSourceDeps) {
173
+ root.dataSourceDeps = {};
174
+ }
175
+ root.dataSourceDeps[target.id] = target.deps;
169
176
  }
170
177
 
171
- root.dataSourceDeps[target.id] = target.deps;
178
+ if (target.type === DepTargetType.DATA_SOURCE_COND) {
179
+ if (!root.dataSourceCondDeps) {
180
+ root.dataSourceCondDeps = {};
181
+ }
182
+ root.dataSourceCondDeps[target.id] = target.deps;
183
+ }
172
184
  };
173
185
 
174
186
  const targetRemoveHandler = (id: string | number) => {
175
187
  const root = editorService.get('root');
176
- if (!root?.dataSourceDeps) return;
177
188
 
178
- delete root.dataSourceDeps[id];
189
+ if (root?.dataSourceDeps) {
190
+ delete root.dataSourceDeps[id];
191
+ }
192
+
193
+ if (root?.dataSourceCondDeps) {
194
+ delete root.dataSourceCondDeps[id];
195
+ }
179
196
  };
180
197
 
181
198
  const depUpdateHandler = (node: MNode) => {
@@ -191,6 +208,12 @@ export const initServiceEvents = (
191
208
  depService.on('dep-update', depUpdateHandler);
192
209
  depService.on('collected', collectedHandler);
193
210
 
211
+ const initDataSourceDepTarget = (ds: DataSourceSchema) => {
212
+ depService.addTarget(createDataSourceTarget(ds.id));
213
+ depService.addTarget(createDataSourceMethodTarget(ds.id));
214
+ depService.addTarget(createDataSourceCondTarget(ds.id));
215
+ };
216
+
194
217
  const rootChangeHandler = async (value: MApp, preValue?: MApp | null) => {
195
218
  const nodeId = editorService.get('node')?.id || props.defaultSelected;
196
219
  let node;
@@ -218,14 +241,14 @@ export const initServiceEvents = (
218
241
  codeBlockService.setCodeDsl(value.codeBlocks);
219
242
  dataSourceService.set('dataSources', value.dataSources);
220
243
 
221
- depService.removeTargets('code-block');
244
+ depService.removeTargets(DepTargetType.CODE_BLOCK);
222
245
 
223
246
  Object.entries(value.codeBlocks).forEach(([id, code]) => {
224
247
  depService.addTarget(createCodeBlockTarget(id, code));
225
248
  });
226
249
 
227
250
  value.dataSources.forEach((ds) => {
228
- depService.addTarget(createDataSourceTarget(ds.id, ds));
251
+ initDataSourceDepTarget(ds);
229
252
  });
230
253
 
231
254
  if (value && Array.isArray(value.items)) {
@@ -279,17 +302,14 @@ export const initServiceEvents = (
279
302
  codeBlockService.on('remove', codeBlockRemoveHandler);
280
303
 
281
304
  const dataSourceAddHandler = (config: DataSourceSchema) => {
282
- depService.addTarget(createDataSourceTarget(config.id, config));
305
+ initDataSourceDepTarget(config);
283
306
  getApp()?.dataSourceManager?.addDataSource(config);
284
307
  };
285
308
 
286
309
  const dataSourceUpdateHandler = (config: DataSourceSchema) => {
287
- if (config.title) {
288
- depService.getTarget(config.id)!.name = config.title;
289
- }
290
310
  const root = editorService.get('root');
291
311
 
292
- const targets = depService.getTargets('data-source');
312
+ const targets = depService.getTargets(DepTargetType.DATA_SOURCE);
293
313
 
294
314
  const nodes = getNodes(Object.keys(targets[config.id].deps), root?.items);
295
315
 
@@ -50,7 +50,7 @@ import type { Id } from '@tmagic/schema';
50
50
  import Icon from '@editor/components/Icon.vue';
51
51
  import AppManageIcon from '@editor/icons/AppManageIcon.vue';
52
52
  import CodeIcon from '@editor/icons/CodeIcon.vue';
53
- import { CodeDeleteErrorType, CodeDslItem, Services } from '@editor/type';
53
+ import { CodeDeleteErrorType, CodeDslItem, DepTargetType, Services } from '@editor/type';
54
54
 
55
55
  defineOptions({
56
56
  name: 'MEditorCodeBlockList',
@@ -69,7 +69,7 @@ const { codeBlockService, depService, editorService } = inject<Services>('servic
69
69
 
70
70
  // 代码块列表
71
71
  const codeList = computed(() =>
72
- Object.values(depService?.targets['code-block'] || {}).map((target) => {
72
+ Object.values(depService?.getTargets(DepTargetType.CODE_BLOCK) || {}).map((target) => {
73
73
  // 组件节点
74
74
  const compNodes = Object.entries(target.deps).map(([id, dep]) => ({
75
75
  name: dep.name,
@@ -2,6 +2,7 @@
2
2
  <MFormDrawer
3
3
  ref="fomDrawer"
4
4
  label-width="80px"
5
+ :close-on-press-escape="false"
5
6
  :title="title"
6
7
  :width="size"
7
8
  :config="dataSourceConfig"
@@ -15,11 +15,11 @@
15
15
  <div class="list-item">
16
16
  <Icon v-if="data.type === 'code'" class="codeIcon" :icon="Coin"></Icon>
17
17
  <Icon v-if="data.type === 'node'" class="compIcon" :icon="Aim"></Icon>
18
- <span class="name" :class="{ code: data.type === 'code', hook: data.type === 'key' }"
19
- >{{ data.name }}({{ data.id }})</span
20
- >
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
21
  <!-- 右侧工具栏 -->
22
- <div class="right-tool" v-if="data.type === 'code'">
22
+ <div class="right-tool" v-if="data.type === 'ds'">
23
23
  <TMagicTooltip effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
24
24
  <Icon :icon="editable ? Edit : View" class="edit-icon" @click.stop="editHandler(`${data.id}`)"></Icon>
25
25
  </TMagicTooltip>
@@ -39,10 +39,10 @@ import { computed, inject, ref } from 'vue';
39
39
  import { Aim, Close, Coin, Edit, View } from '@element-plus/icons-vue';
40
40
 
41
41
  import { tMagicMessageBox, TMagicTooltip, TMagicTree } from '@tmagic/design';
42
- import { Id } from '@tmagic/schema';
42
+ import { Dep, Id } from '@tmagic/schema';
43
43
 
44
44
  import Icon from '@editor/components/Icon.vue';
45
- import type { Services } from '@editor/type';
45
+ import { DepTargetType, Services } from '@editor/type';
46
46
 
47
47
  defineOptions({
48
48
  name: 'MEditorDataSourceList',
@@ -57,18 +57,52 @@ const { depService, editorService, dataSourceService } = inject<Services>('servi
57
57
 
58
58
  const editable = computed(() => dataSourceService?.get('editable') ?? true);
59
59
 
60
+ const dataSources = computed(() => dataSourceService?.get('dataSources') || []);
61
+
62
+ const dsDep = computed(() => depService?.getTargets(DepTargetType.DATA_SOURCE) || {});
63
+ const dsMethodDep = computed(() => depService?.getTargets(DepTargetType.DATA_SOURCE_METHOD) || {});
64
+ const dsCondDep = computed(() => depService?.getTargets(DepTargetType.DATA_SOURCE_COND) || {});
65
+
66
+ const getKeyTreeConfig = (dep: Dep[string], type?: string) =>
67
+ dep.keys.map((key) => ({ name: key, id: key, type: 'key', isMethod: type === 'method', isCond: type === 'cond' }));
68
+
69
+ const getNodeTreeConfig = (id: string, dep: Dep[string], type?: string) => ({
70
+ name: dep.name,
71
+ type: 'node',
72
+ id,
73
+ children: getKeyTreeConfig(dep, type),
74
+ });
75
+
60
76
  const list = computed(() =>
61
- Object.values(depService?.targets['data-source'] || {}).map((target) => ({
62
- id: target.id,
63
- name: target.name,
64
- type: 'code',
65
- children: Object.entries(target.deps).map(([id, dep]) => ({
66
- name: dep.name,
67
- type: 'node',
68
- id,
69
- children: dep.keys.map((key) => ({ name: key, id: key, type: 'key' })),
70
- })),
71
- })),
77
+ dataSources.value.map((ds) => {
78
+ const dsDeps = dsDep.value[ds.id].deps;
79
+ const dsMethodDeps = dsMethodDep.value[ds.id].deps;
80
+ const dsCondDeps = dsCondDep.value[ds.id].deps;
81
+
82
+ const children: any[] = [];
83
+
84
+ const mergeChildren = (deps: Dep, type?: string) => {
85
+ Object.entries(deps).forEach(([id, dep]) => {
86
+ const nodeItem = children.find((item) => item.id === id);
87
+ if (nodeItem) {
88
+ nodeItem.children = nodeItem.children.concat(getKeyTreeConfig(dep, type));
89
+ } else {
90
+ children.push(getNodeTreeConfig(id, dep, type));
91
+ }
92
+ });
93
+ };
94
+
95
+ mergeChildren(dsDeps);
96
+ mergeChildren(dsMethodDeps, 'method');
97
+ mergeChildren(dsCondDeps, 'cond');
98
+
99
+ return {
100
+ id: ds.id,
101
+ name: ds.title,
102
+ type: 'ds',
103
+ children,
104
+ };
105
+ }),
72
106
  );
73
107
 
74
108
  const editHandler = (id: string) => {
@@ -19,27 +19,24 @@ import { EventEmitter } from 'events';
19
19
 
20
20
  import { reactive } from 'vue';
21
21
 
22
- import { Id, MNode } from '@tmagic/schema';
22
+ import type { Dep, Id, MNode } from '@tmagic/schema';
23
+ import { isObject } from '@tmagic/utils';
24
+
25
+ import { DepTargetType } from '@editor/type';
23
26
 
24
27
  type IsTarget = (key: string | number, value: any) => boolean;
25
28
 
26
29
  interface TargetOptions {
27
30
  isTarget: IsTarget;
28
31
  id: string | number;
29
- type?: string;
30
- name: string;
31
- }
32
-
33
- interface Dep {
34
- [key: string | number]: {
35
- name: string;
36
- keys: (string | number)[];
37
- };
32
+ /** 类型,数据源、代码块或其他 */
33
+ type?: DepTargetType | string;
34
+ name?: string;
38
35
  }
39
36
 
40
37
  interface TargetList {
41
- [key: string]: {
42
- [key: string | number]: Target;
38
+ [type: DepTargetType | string]: {
39
+ [targetId: string | number]: Target;
43
40
  };
44
41
  }
45
42
 
@@ -60,11 +57,11 @@ export class Target extends EventEmitter {
60
57
  /**
61
58
  * 目标名称,用于显示在依赖列表中
62
59
  */
63
- public name: string;
60
+ public name?: string;
64
61
  /**
65
62
  * 不同的目标可以进行分类,例如代码块,数据源可以为两个不同的type
66
63
  */
67
- public type = 'default';
64
+ public type: DepTargetType | string = DepTargetType.DEFAULT;
68
65
  /**
69
66
  * 依赖详情
70
67
  * 实例:{ 'node_id': { name: 'node_name', keys: [ created, mounted ] } }
@@ -156,14 +153,14 @@ export class Target extends EventEmitter {
156
153
  }
157
154
 
158
155
  export class Watcher extends EventEmitter {
159
- public targets = reactive<TargetList>({});
156
+ private targets = reactive<TargetList>({});
160
157
 
161
158
  /**
162
159
  * 获取指定类型中的所有target
163
160
  * @param type 分类
164
161
  * @returns Target[]
165
162
  */
166
- public getTargets(type = 'default') {
163
+ public getTargets(type: DepTargetType | string = DepTargetType.DEFAULT) {
167
164
  return this.targets[type] || {};
168
165
  }
169
166
 
@@ -230,7 +227,7 @@ export class Watcher extends EventEmitter {
230
227
  * @param type 分类
231
228
  * @returns void
232
229
  */
233
- public removeTargets(type = 'default') {
230
+ public removeTargets(type: DepTargetType | string = DepTargetType.DEFAULT) {
234
231
  const targets = this.targets[type];
235
232
 
236
233
  if (!targets) return;
@@ -307,9 +304,11 @@ export class Watcher extends EventEmitter {
307
304
  this.emit('update-dep', node, fullKey);
308
305
  } else if (!keyIsItems && Array.isArray(value)) {
309
306
  value.forEach((item, index) => {
310
- collectTarget(item, `${fullKey}.${index}`);
307
+ if (isObject(item)) {
308
+ collectTarget(item, `${fullKey}.${index}`);
309
+ }
311
310
  });
312
- } else if (Object.prototype.toString.call(value) === '[object Object]') {
311
+ } else if (isObject(value)) {
313
312
  collectTarget(value, fullKey);
314
313
  }
315
314
 
@@ -321,6 +320,7 @@ export class Watcher extends EventEmitter {
321
320
  };
322
321
 
323
322
  Object.entries(config).forEach(([key, value]) => {
323
+ if (typeof value === 'undefined' || value === '') return;
324
324
  doCollect(key, value);
325
325
  });
326
326
  };
@@ -27,6 +27,6 @@
27
27
  position: absolute;
28
28
  top: 5px;
29
29
  right: 0;
30
- z-index: 1;
30
+ z-index: 11;
31
31
  }
32
32
  }
package/src/type.ts CHANGED
@@ -500,3 +500,23 @@ export interface DataSourceMethodSelectConfig {
500
500
  disabled?: boolean | FilterFunction;
501
501
  display?: boolean | FilterFunction;
502
502
  }
503
+
504
+ export interface DataSourceFieldSelectConfig {
505
+ type: 'data-source-field-select';
506
+ name: string;
507
+ labelWidth?: number | string;
508
+ disabled?: boolean | FilterFunction;
509
+ display?: boolean | FilterFunction;
510
+ }
511
+
512
+ export enum DepTargetType {
513
+ DEFAULT = 'default',
514
+ /** 代码块 */
515
+ CODE_BLOCK = 'code-block',
516
+ /** 数据源 */
517
+ DATA_SOURCE = 'data-source',
518
+ /** 数据源方法 */
519
+ DATA_SOURCE_METHOD = 'data-source-method',
520
+ /** 数据源条件 */
521
+ DATA_SOURCE_COND = 'data-source-cond',
522
+ }
package/src/utils/dep.ts CHANGED
@@ -1,13 +1,14 @@
1
1
  import { isEmpty } from 'lodash-es';
2
2
 
3
- import { CodeBlockContent, DataSourceSchema, HookType, Id } from '@tmagic/schema';
3
+ import { CodeBlockContent, HookType, Id } from '@tmagic/schema';
4
4
 
5
+ import dataSourceService from '@editor/services/dataSource';
5
6
  import { Target } from '@editor/services/dep';
6
- import type { HookData } from '@editor/type';
7
+ import { DepTargetType, HookData } from '@editor/type';
7
8
 
8
9
  export const createCodeBlockTarget = (id: Id, codeBlock: CodeBlockContent) =>
9
10
  new Target({
10
- type: 'code-block',
11
+ type: DepTargetType.CODE_BLOCK,
11
12
  id,
12
13
  name: codeBlock.name,
13
14
  isTarget: (key: string | number, value: any) => {
@@ -24,12 +25,37 @@ export const createCodeBlockTarget = (id: Id, codeBlock: CodeBlockContent) =>
24
25
  },
25
26
  });
26
27
 
27
- export const createDataSourceTarget = (id: Id, ds: DataSourceSchema) =>
28
+ export const createDataSourceTarget = (id: Id) =>
28
29
  new Target({
29
- type: 'data-source',
30
+ type: DepTargetType.DATA_SOURCE,
30
31
  id,
31
- name: ds.title || `${id}`,
32
32
  isTarget: (key: string | number, value: any) =>
33
33
  // 关联数据源对象或者在模板在使用数据源
34
- (value.isBindDataSource && value.dataSourceId) || (typeof value === 'string' && value.includes(`${id}`)),
34
+ (value?.isBindDataSource && value.dataSourceId) || (typeof value === 'string' && value.includes(`${id}`)),
35
+ });
36
+
37
+ export const createDataSourceCondTarget = (id: string) =>
38
+ new Target({
39
+ type: DepTargetType.DATA_SOURCE_COND,
40
+ id,
41
+ isTarget: (key: string | number, value: any) => {
42
+ if (!Array.isArray(value) || value[0] !== id) return false;
43
+
44
+ const ds = dataSourceService.getDataSourceById(id);
45
+
46
+ return Boolean(ds?.fields?.find((field) => field.name === value[1]));
47
+ },
48
+ });
49
+
50
+ export const createDataSourceMethodTarget = (id: string) =>
51
+ new Target({
52
+ type: DepTargetType.DATA_SOURCE_METHOD,
53
+ id,
54
+ isTarget: (key: string | number, value: any) => {
55
+ if (!Array.isArray(value) || value[0] !== id) return false;
56
+
57
+ const ds = dataSourceService.getDataSourceById(id);
58
+
59
+ return Boolean(ds?.methods?.find((method) => method.name === value[1]));
60
+ },
35
61
  });