@tmagic/editor 1.3.0-alpha.8 → 1.3.0-beta.0

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 (124) hide show
  1. package/dist/style.css +82 -218
  2. package/dist/tmagic-editor.js +4985 -3999
  3. package/dist/tmagic-editor.js.map +1 -1
  4. package/dist/tmagic-editor.umd.cjs +5013 -4012
  5. package/dist/tmagic-editor.umd.cjs.map +1 -1
  6. package/package.json +15 -15
  7. package/src/Editor.vue +4 -5
  8. package/src/components/CodeBlockEditor.vue +257 -0
  9. package/src/components/CodeParams.vue +60 -0
  10. package/src/components/ContentMenu.vue +11 -3
  11. package/src/editorProps.ts +30 -5
  12. package/src/fields/Code.vue +23 -19
  13. package/src/fields/CodeLink.vue +6 -7
  14. package/src/fields/CodeSelect.vue +12 -9
  15. package/src/fields/CodeSelectCol.vue +70 -81
  16. package/src/fields/DataSourceFieldSelect.vue +47 -0
  17. package/src/fields/DataSourceFields.vue +28 -22
  18. package/src/fields/DataSourceInput.vue +21 -58
  19. package/src/fields/DataSourceMethodSelect.vue +136 -0
  20. package/src/fields/DataSourceMethods.vue +103 -0
  21. package/src/fields/DataSourceSelect.vue +68 -0
  22. package/src/fields/EventSelect.vue +53 -19
  23. package/src/fields/KeyValue.vue +9 -11
  24. package/src/fields/UISelect.vue +54 -14
  25. package/src/hooks/index.ts +21 -0
  26. package/src/hooks/use-code-block-edit.ts +84 -0
  27. package/src/hooks/use-data-source-method.ts +100 -0
  28. package/src/{utils/stage.ts → hooks/use-stage.ts} +4 -7
  29. package/src/icons/CenterIcon.vue +13 -0
  30. package/src/icons/CodeIcon.vue +0 -2
  31. package/src/icons/FolderMinusIcon.vue +22 -0
  32. package/src/index.ts +15 -0
  33. package/src/initService.ts +73 -16
  34. package/src/layouts/CodeEditor.vue +62 -10
  35. package/src/layouts/Framework.vue +7 -3
  36. package/src/layouts/PropsPanel.vue +8 -3
  37. package/src/layouts/sidebar/ComponentListPanel.vue +6 -9
  38. package/src/layouts/sidebar/LayerMenu.vue +20 -21
  39. package/src/layouts/sidebar/LayerNode.vue +40 -0
  40. package/src/layouts/sidebar/LayerPanel.vue +14 -5
  41. package/src/layouts/sidebar/Sidebar.vue +22 -36
  42. package/src/layouts/sidebar/code-block/CodeBlockList.vue +81 -119
  43. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +64 -0
  44. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +27 -47
  45. package/src/layouts/sidebar/data-source/DataSourceList.vue +145 -0
  46. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +58 -69
  47. package/src/layouts/workspace/Stage.vue +13 -5
  48. package/src/layouts/workspace/ViewerMenu.vue +10 -35
  49. package/src/services/codeBlock.ts +18 -71
  50. package/src/services/dataSource.ts +16 -1
  51. package/src/services/dep.ts +23 -20
  52. package/src/services/editor.ts +46 -18
  53. package/src/services/props.ts +2 -2
  54. package/src/theme/code-block.scss +5 -117
  55. package/src/theme/code-editor.scss +27 -2
  56. package/src/theme/content-menu.scss +1 -1
  57. package/src/theme/data-source-methods.scss +13 -0
  58. package/src/theme/data-source.scss +11 -0
  59. package/src/theme/event.scss +15 -12
  60. package/src/theme/framework.scss +0 -3
  61. package/src/theme/layer-panel.scss +6 -0
  62. package/src/theme/layout.scss +4 -0
  63. package/src/theme/sidebar.scss +18 -60
  64. package/src/theme/theme.scss +1 -0
  65. package/src/type.ts +47 -7
  66. package/src/utils/content-menu.ts +92 -0
  67. package/src/utils/data-source/formConfigs/base.ts +28 -30
  68. package/src/utils/data-source/index.ts +65 -2
  69. package/src/utils/dep.ts +39 -7
  70. package/src/utils/index.ts +1 -1
  71. package/src/utils/props.ts +298 -189
  72. package/src/utils/undo-redo.ts +1 -1
  73. package/types/Editor.vue.d.ts +30 -6
  74. package/types/components/CodeBlockEditor.vue.d.ts +23 -0
  75. package/types/components/CodeParams.vue.d.ts +26 -0
  76. package/types/components/ContentMenu.vue.d.ts +2 -2
  77. package/types/components/ToolButton.vue.d.ts +3 -3
  78. package/types/editorProps.d.ts +19 -5
  79. package/types/fields/Code.vue.d.ts +24 -19
  80. package/types/fields/CodeLink.vue.d.ts +12 -21
  81. package/types/fields/CodeSelect.vue.d.ts +6 -17
  82. package/types/fields/CodeSelectCol.vue.d.ts +10 -14
  83. package/types/fields/DataSourceFieldSelect.vue.d.ts +29 -0
  84. package/types/fields/DataSourceFields.vue.d.ts +7 -18
  85. package/types/fields/DataSourceInput.vue.d.ts +10 -30
  86. package/types/fields/DataSourceMethodSelect.vue.d.ts +29 -0
  87. package/types/fields/DataSourceMethods.vue.d.ts +32 -0
  88. package/types/fields/DataSourceSelect.vue.d.ts +40 -0
  89. package/types/fields/EventSelect.vue.d.ts +2 -13
  90. package/types/fields/KeyValue.vue.d.ts +9 -24
  91. package/types/fields/UISelect.vue.d.ts +2 -11
  92. package/types/hooks/index.d.ts +3 -0
  93. package/types/{components/FunctionEditor.vue.d.ts → hooks/use-code-block-edit.d.ts} +31 -119
  94. package/types/hooks/use-data-source-method.d.ts +123 -0
  95. package/types/icons/CenterIcon.vue.d.ts +2 -0
  96. package/types/icons/FolderMinusIcon.vue.d.ts +2 -0
  97. package/types/index.d.ts +7 -0
  98. package/types/initService.d.ts +2 -2
  99. package/types/layouts/CodeEditor.vue.d.ts +10 -4
  100. package/types/layouts/PropsPanel.vue.d.ts +274 -2
  101. package/types/layouts/sidebar/LayerNode.vue.d.ts +16 -0
  102. package/types/layouts/sidebar/Sidebar.vue.d.ts +0 -3
  103. package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +4 -9
  104. package/types/layouts/sidebar/code-block/{CodeBlockEditor.vue.d.ts → CodeBlockListPanel.vue.d.ts} +9 -5
  105. package/types/layouts/sidebar/data-source/DataSourceConfigPanel.vue.d.ts +3 -1
  106. package/types/layouts/sidebar/data-source/DataSourceList.vue.d.ts +14 -0
  107. package/types/layouts/sidebar/data-source/DataSourceListPanel.vue.d.ts +1 -11
  108. package/types/services/codeBlock.d.ts +6 -37
  109. package/types/services/dataSource.d.ts +7 -1
  110. package/types/services/dep.d.ts +12 -21
  111. package/types/services/editor.d.ts +1 -1
  112. package/types/services/props.d.ts +10 -115
  113. package/types/type.d.ts +42 -7
  114. package/types/utils/content-menu.d.ts +7 -0
  115. package/types/utils/data-source/formConfigs/base.d.ts +1 -2
  116. package/types/utils/data-source/index.d.ts +5 -0
  117. package/types/utils/dep.d.ts +4 -2
  118. package/types/utils/index.d.ts +1 -1
  119. package/types/utils/props.d.ts +13 -102
  120. package/src/components/CodeDraftEditor.vue +0 -148
  121. package/src/components/FunctionEditor.vue +0 -197
  122. package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +0 -100
  123. package/types/components/CodeDraftEditor.vue.d.ts +0 -61
  124. /package/types/{utils/stage.d.ts → hooks/use-stage.d.ts} +0 -0
@@ -9,10 +9,26 @@
9
9
  @change="onParamsChangeHandler"
10
10
  ></m-form-container>
11
11
  <!-- 查看/编辑按钮 -->
12
- <Icon class="icon" :icon="editable ? Edit : View" @click="editCode"></Icon>
12
+ <Icon v-if="model[name]" class="icon" :icon="!disabled ? Edit : View" @click="editCode(model[name])"></Icon>
13
13
  </div>
14
+
14
15
  <!-- 参数填写框 -->
15
- <m-form-container :config="codeParamsConfig" :model="model" @change="onParamsChangeHandler"></m-form-container>
16
+ <CodeParams
17
+ v-if="paramsConfig.length"
18
+ name="params"
19
+ :model="model"
20
+ :size="size"
21
+ :params-config="paramsConfig"
22
+ @change="onParamsChangeHandler"
23
+ ></CodeParams>
24
+
25
+ <CodeBlockEditor
26
+ ref="codeBlockEditor"
27
+ v-if="codeConfig"
28
+ :disabled="disabled"
29
+ :content="codeConfig"
30
+ @submit="submitCodeBlockHandler"
31
+ ></CodeBlockEditor>
16
32
  </div>
17
33
  </template>
18
34
 
@@ -21,45 +37,61 @@ import { computed, inject, ref, watch } from 'vue';
21
37
  import { Edit, View } from '@element-plus/icons-vue';
22
38
  import { isEmpty, map } from 'lodash-es';
23
39
 
24
- import { createValues, FieldsetConfig, FormState } from '@tmagic/form';
25
- import { Id } from '@tmagic/schema';
40
+ import { createValues, FieldProps } from '@tmagic/form';
41
+ import type { Id } from '@tmagic/schema';
26
42
 
43
+ import CodeBlockEditor from '@editor/components/CodeBlockEditor.vue';
44
+ import CodeParams from '@editor/components/CodeParams.vue';
27
45
  import Icon from '@editor/components/Icon.vue';
28
- import type { CodeParamStatement, Services } from '@editor/type';
46
+ import { useCodeBlockEdit } from '@editor/hooks/use-code-block-edit';
47
+ import type { CodeParamStatement, CodeSelectColConfig, Services } from '@editor/type';
29
48
 
30
49
  defineOptions({
31
50
  name: 'MEditorCodeSelectCol',
32
51
  });
33
52
 
34
53
  const services = inject<Services>('services');
35
- const mForm = inject<FormState>('mForm');
36
54
  const emit = defineEmits(['change']);
37
55
 
38
- const props = withDefaults(
39
- defineProps<{
40
- config: any;
41
- model: any;
42
- prop: string;
43
- name: string;
44
- size: 'small' | 'default' | 'large';
45
- }>(),
46
- {},
47
- );
48
- const codeDsl = computed(() => services?.codeBlockService.getCodeDsl());
49
- const editable = computed(() => services?.codeBlockService.getEditStatus());
50
- const codeParamsConfig = ref<FieldsetConfig>({
51
- type: 'fieldset',
52
- items: [],
53
- legend: '参数',
54
- labelWidth: '70px',
55
- name: 'params',
56
- display: false,
56
+ const props = withDefaults(defineProps<FieldProps<CodeSelectColConfig>>(), {
57
+ disabled: false,
57
58
  });
59
+
60
+ /**
61
+ * 根据代码块id获取代码块参数配置
62
+ * @param codeId 代码块ID
63
+ */
64
+ const getParamItemsConfig = (codeId?: Id): CodeParamStatement[] => {
65
+ if (!codeDsl.value || !codeId) return [];
66
+
67
+ const paramStatements = codeDsl.value[codeId]?.params;
68
+
69
+ if (isEmpty(paramStatements)) return [];
70
+
71
+ return paramStatements.map((paramState: CodeParamStatement) => ({
72
+ labelWidth: '100px',
73
+ text: paramState.name,
74
+ ...paramState,
75
+ }));
76
+ };
77
+
78
+ const codeDsl = computed(() => services?.codeBlockService.getCodeDsl());
79
+ const paramsConfig = ref<CodeParamStatement[]>(getParamItemsConfig(props.model[props.name]));
80
+
81
+ watch(
82
+ () => props.model[props.name],
83
+ (v, preV) => {
84
+ if (v !== preV) {
85
+ paramsConfig.value = getParamItemsConfig(v);
86
+ }
87
+ },
88
+ );
89
+
58
90
  const selectConfig = {
59
91
  type: 'select',
60
92
  text: '代码块',
61
- name: 'codeId',
62
- labelWidth: '70px',
93
+ name: props.name,
94
+ labelWidth: '80px',
63
95
  options: () => {
64
96
  if (codeDsl.value) {
65
97
  return map(codeDsl.value, (value, key) => ({
@@ -72,68 +104,25 @@ const selectConfig = {
72
104
  },
73
105
  onChange: (formState: any, codeId: Id, { model }: any) => {
74
106
  // 通过下拉框选择的codeId变化后修正model的值,避免写入其他codeId的params
75
- model.params = {};
76
- },
77
- };
107
+ paramsConfig.value = getParamItemsConfig(codeId);
78
108
 
79
- /**
80
- * 根据代码块id获取代码块参数配置
81
- * @param codeId 代码块ID
82
- */
83
- const getParamItemsConfig = (codeId: Id): CodeParamStatement[] => {
84
- if (!codeDsl.value) return [];
85
- const paramStatements = codeDsl.value[codeId]?.params;
86
- if (isEmpty(paramStatements)) return [];
87
- return paramStatements.map((paramState: CodeParamStatement) => ({
88
- labelWidth: '100px',
89
- text: paramState.name,
90
- ...paramState,
91
- }));
92
- };
109
+ if (paramsConfig.value.length) {
110
+ model.params = createValues(formState, paramsConfig.value, {}, model.params);
111
+ } else {
112
+ model.params = {};
113
+ }
93
114
 
94
- /**
95
- * 根据代码块id获取参数fieldset表单配置
96
- * @param codeId 代码块ID
97
- */
98
- const getCodeParamsConfig = (codeId: Id) => {
99
- const paramsConfig = getParamItemsConfig(codeId);
100
- // 如果参数没有填值,则使用createValues补全空值
101
- if (!props.model.params || isEmpty(props.model.params)) {
102
- props.model.params = {};
103
- createValues(mForm, paramsConfig, {}, props.model.params);
104
- }
105
- codeParamsConfig.value = {
106
- type: 'fieldset',
107
- items: paramsConfig,
108
- legend: '参数',
109
- labelWidth: '70px',
110
- name: 'params',
111
- display: !isEmpty(paramsConfig),
112
- };
115
+ return codeId;
116
+ },
113
117
  };
114
118
 
115
119
  /**
116
120
  * 参数值修改更新
117
121
  */
118
- const onParamsChangeHandler = () => {
122
+ const onParamsChangeHandler = (value: any) => {
123
+ props.model.params = value.params;
119
124
  emit('change', props.model);
120
125
  };
121
126
 
122
- // 监听代码块顺序变化以及下拉选择的变化,并更新参数配置
123
- // TODO onchange在watch之前触发
124
- watch(
125
- () => props.model.codeId,
126
- (codeId: Id) => {
127
- if (!codeId) return;
128
- getCodeParamsConfig(codeId);
129
- },
130
- {
131
- immediate: true,
132
- },
133
- );
134
-
135
- // 打开代码编辑框
136
- const editCode = () => {
137
- services?.codeBlockService.setCodeEditorContent(true, props.model.codeId);
138
- };
127
+ const { codeBlockEditor, codeConfig, editCode, submitCodeBlockHandler } = useCodeBlockEdit(services?.codeBlockService);
139
128
  </script>
@@ -0,0 +1,47 @@
1
+ <template>
2
+ <m-form-container
3
+ :config="{
4
+ ...config,
5
+ ...cascaderConfig,
6
+ }"
7
+ :model="model"
8
+ @change="onChangeHandler"
9
+ ></m-form-container>
10
+ </template>
11
+
12
+ <script setup lang="ts">
13
+ import { computed, inject } from 'vue';
14
+
15
+ import type { FieldProps } from '@tmagic/form';
16
+
17
+ import type { DataSourceFieldSelectConfig, Services } from '@editor/type';
18
+
19
+ const services = inject<Services>('services');
20
+ const emit = defineEmits(['change']);
21
+
22
+ const props = withDefaults(defineProps<FieldProps<DataSourceFieldSelectConfig>>(), {
23
+ disabled: false,
24
+ });
25
+
26
+ const dataSources = computed(() => services?.dataSourceService.get('dataSources'));
27
+
28
+ const cascaderConfig = {
29
+ type: 'cascader',
30
+ name: props.name,
31
+ options: () =>
32
+ dataSources.value
33
+ ?.filter((ds) => ds.fields?.length)
34
+ ?.map((ds) => ({
35
+ label: ds.title || ds.id,
36
+ value: ds.id,
37
+ children: ds.fields?.map((field) => ({
38
+ label: field.title,
39
+ value: field.name,
40
+ })),
41
+ })) || [],
42
+ };
43
+
44
+ const onChangeHandler = (value: any) => {
45
+ emit('change', value);
46
+ };
47
+ </script>
@@ -1,43 +1,44 @@
1
1
  <template>
2
2
  <div class="m-editor-data-source-fields">
3
- <MagicTable :data="model[name]" :columns="filedColumns"></MagicTable>
3
+ <MagicTable :data="model[name]" :columns="fieldColumns"></MagicTable>
4
4
 
5
5
  <div class="m-editor-data-source-fields-footer">
6
6
  <TMagicButton size="small" type="primary" :disabled="disabled" plain @click="newHandler()">添加</TMagicButton>
7
7
  </div>
8
8
 
9
- <MFormDialog
9
+ <MFormDrawer
10
10
  ref="addDialog"
11
+ label-width="80px"
11
12
  :title="filedTitle"
12
13
  :config="dataSourceFieldsConfig"
13
14
  :values="fieldValues"
14
15
  :parentValues="model[name]"
16
+ :disabled="disabled"
17
+ :width="width"
15
18
  @submit="fieldChange"
16
- ></MFormDialog>
19
+ ></MFormDrawer>
17
20
  </div>
18
21
  </template>
19
22
 
20
23
  <script setup lang="ts">
21
- import { ref } from 'vue';
24
+ import { computed, inject, ref } from 'vue';
22
25
 
23
26
  import { TMagicButton, tMagicMessageBox } from '@tmagic/design';
24
- import { FormConfig, FormState, MFormDialog } from '@tmagic/form';
27
+ import { type FieldProps, type FormConfig, type FormState, MFormDrawer } from '@tmagic/form';
25
28
  import { MagicTable } from '@tmagic/table';
26
29
 
30
+ import type { Services } from '@editor/type';
31
+
27
32
  defineOptions({
28
33
  name: 'MEditorDataSourceFields',
29
34
  });
30
35
 
31
36
  const props = withDefaults(
32
- defineProps<{
33
- config: {
37
+ defineProps<
38
+ FieldProps<{
34
39
  type: 'data-source-fields';
35
- };
36
- model: any;
37
- prop: string;
38
- disabled: boolean;
39
- name: string;
40
- }>(),
40
+ }>
41
+ >(),
41
42
  {
42
43
  disabled: false,
43
44
  },
@@ -45,32 +46,33 @@ const props = withDefaults(
45
46
 
46
47
  const emit = defineEmits(['change']);
47
48
 
48
- const addDialog = ref<InstanceType<typeof MFormDialog>>();
49
+ const services = inject<Services>('services');
50
+
51
+ const addDialog = ref<InstanceType<typeof MFormDrawer>>();
49
52
  const fieldValues = ref<Record<string, any>>({});
50
53
  const filedTitle = ref('');
51
54
 
55
+ const width = computed(() => globalThis.document.body.clientWidth - (services?.uiService.get('columnWidth').left || 0));
56
+
52
57
  const newHandler = () => {
53
- if (!addDialog.value) return;
54
58
  fieldValues.value = {};
55
59
  filedTitle.value = '新增属性';
56
- addDialog.value.dialogVisible = true;
60
+ addDialog.value?.show();
57
61
  };
58
62
 
59
63
  const fieldChange = ({ index, ...value }: Record<string, any>) => {
60
- if (!addDialog.value) return;
61
-
62
64
  if (index > -1) {
63
65
  props.model[props.name][index] = value;
64
66
  } else {
65
67
  props.model[props.name].push(value);
66
68
  }
67
69
 
68
- addDialog.value.dialogVisible = false;
70
+ addDialog.value?.hide();
69
71
 
70
72
  emit('change', props.model[props.name]);
71
73
  };
72
74
 
73
- const filedColumns = [
75
+ const fieldColumns = [
74
76
  {
75
77
  label: '属性名称',
76
78
  prop: 'title',
@@ -83,6 +85,10 @@ const filedColumns = [
83
85
  label: '属性描述',
84
86
  prop: 'desc',
85
87
  },
88
+ {
89
+ label: '默认值',
90
+ prop: 'defaultValue',
91
+ },
86
92
  {
87
93
  label: '操作',
88
94
  fixed: 'right',
@@ -90,13 +96,12 @@ const filedColumns = [
90
96
  {
91
97
  text: '编辑',
92
98
  handler: (row: Record<string, any>, index: number) => {
93
- if (!addDialog.value) return;
94
99
  fieldValues.value = {
95
100
  ...row,
96
101
  index,
97
102
  };
98
103
  filedTitle.value = `编辑${row.title}`;
99
- addDialog.value.dialogVisible = true;
104
+ addDialog.value?.show();
100
105
  },
101
106
  },
102
107
  {
@@ -161,6 +166,7 @@ const dataSourceFieldsConfig: FormConfig = [
161
166
  {
162
167
  name: 'description',
163
168
  text: '描述',
169
+ type: 'textarea',
164
170
  },
165
171
  {
166
172
  name: 'defaultValue',
@@ -16,7 +16,6 @@
16
16
  "
17
17
  style="width: 100%"
18
18
  @blur="blurHandler"
19
- @change="changeHandler"
20
19
  @input="inputHandler"
21
20
  @select="selectHandler"
22
21
  >
@@ -48,36 +47,34 @@
48
47
  import { computed, inject, nextTick, ref, watch } from 'vue';
49
48
  import { Coin } from '@element-plus/icons-vue';
50
49
 
51
- import { FieldSize, getConfig, TMagicAutocomplete, TMagicTag } from '@tmagic/design';
50
+ import { getConfig, TMagicAutocomplete, TMagicTag } from '@tmagic/design';
51
+ import type { FieldProps } from '@tmagic/form';
52
52
  import type { DataSchema, DataSourceSchema } from '@tmagic/schema';
53
53
 
54
54
  import Icon from '@editor/components/Icon.vue';
55
55
  import type { Services } from '@editor/type';
56
+ import { getDisplayField } from '@editor/utils/data-source';
56
57
 
57
58
  defineOptions({
58
59
  name: 'MEditorDataSourceInput',
59
60
  });
60
61
 
61
62
  const props = withDefaults(
62
- defineProps<{
63
- config: {
63
+ defineProps<
64
+ FieldProps<{
64
65
  type: 'data-source-input';
65
66
  name: string;
66
67
  text: string;
67
- };
68
- model: Record<string, any>;
69
- name: string;
70
- prop: string;
71
- disabled: boolean;
72
- lastValues?: Record<string, any>;
73
- size?: FieldSize;
74
- }>(),
68
+ }>
69
+ >(),
75
70
  {
76
71
  disabled: false,
77
72
  },
78
73
  );
79
74
 
80
- const emit = defineEmits<(e: 'change', value: string) => void>();
75
+ const emit = defineEmits<{
76
+ change: [value: string];
77
+ }>();
81
78
 
82
79
  const { dataSourceService } = inject<Services>('services') || {};
83
80
 
@@ -90,49 +87,7 @@ const input = computed<HTMLInputElement>(() => autocomplete.value?.inputRef?.inp
90
87
  const dataSources = computed(() => dataSourceService?.get('dataSources') || []);
91
88
 
92
89
  const setDisplayState = () => {
93
- displayState.value = [];
94
-
95
- const matches = state.value.matchAll(/\$\{([\s\S]+?)\}/g);
96
- let index = 0;
97
- for (const match of matches) {
98
- if (typeof match.index === 'undefined') break;
99
-
100
- displayState.value.push({
101
- type: 'text',
102
- value: state.value.substring(index, match.index),
103
- });
104
-
105
- let dsText = '';
106
- let ds: DataSourceSchema | undefined;
107
- let fields: DataSchema[] | undefined;
108
-
109
- match[1].split('.').forEach((item, index) => {
110
- if (index === 0) {
111
- ds = dataSources.value.find((ds) => ds.id === item);
112
- dsText += ds?.title || item;
113
- fields = ds?.fields;
114
- return;
115
- }
116
-
117
- const field = fields?.find((field) => field.name === item);
118
- fields = field?.fields;
119
- dsText += `.${field?.title || item}`;
120
- });
121
-
122
- displayState.value.push({
123
- type: 'var',
124
- value: dsText,
125
- });
126
-
127
- index = match.index + match[0].length;
128
- }
129
-
130
- if (index < state.value.length) {
131
- displayState.value.push({
132
- type: 'text',
133
- value: state.value.substring(index),
134
- });
135
- }
90
+ displayState.value = getDisplayField(dataSources.value, state.value);
136
91
  };
137
92
 
138
93
  watch(
@@ -155,6 +110,8 @@ const blurHandler = () => {
155
110
  isFocused.value = false;
156
111
 
157
112
  setDisplayState();
113
+
114
+ emit('change', state.value);
158
115
  };
159
116
 
160
117
  const changeHandler = (v: string) => {
@@ -246,17 +203,21 @@ const fieldQuerySearch = (
246
203
  let result: DataSchema[] = [];
247
204
 
248
205
  const dsKey = queryString.substring(leftAngleIndex + 1, dotIndex);
206
+
249
207
  // 可能是xx.xx.xx,存在链式调用
250
208
  const keys = dsKey.split('.');
209
+
251
210
  // 最前的是数据源id
252
- const ds = dataSources.value.find((ds) => ds.id === keys.shift());
211
+ const dsId = keys.shift();
212
+ const ds = dataSources.value.find((ds) => ds.id === dsId);
253
213
  if (!ds) {
214
+ cb([]);
254
215
  return;
255
216
  }
256
217
 
257
218
  let fields = ds.fields || [];
258
219
 
259
- // 后面这些事字段
220
+ // 后面这些是字段
260
221
  let key = keys.shift();
261
222
  while (key) {
262
223
  for (const field of fields) {
@@ -354,5 +315,7 @@ const selectHandler = async ({ value, type }: { value: string; type: 'dataSource
354
315
  newSelectionStart = dotIndex + suggestText.length + 1;
355
316
  }
356
317
  input.value?.setSelectionRange(newSelectionStart, newSelectionStart);
318
+
319
+ changeHandler(state.value);
357
320
  };
358
321
  </script>
@@ -0,0 +1,136 @@
1
+ <template>
2
+ <div class="m-fields-data-source-method-select">
3
+ <div class="data-source-method-select-container">
4
+ <m-form-container
5
+ class="select"
6
+ :config="cascaderConfig"
7
+ :model="model"
8
+ @change="onChangeHandler"
9
+ ></m-form-container>
10
+ <Icon v-if="model[name]" class="icon" :icon="!disabled ? Edit : View" @click="editCodeHandler"></Icon>
11
+ </div>
12
+
13
+ <CodeParams
14
+ v-if="paramsConfig.length"
15
+ name="params"
16
+ :model="model"
17
+ :size="size"
18
+ :disabled="disabled"
19
+ :params-config="paramsConfig"
20
+ @change="onChangeHandler"
21
+ ></CodeParams>
22
+
23
+ <CodeBlockEditor
24
+ ref="codeBlockEditor"
25
+ v-if="codeConfig"
26
+ :disabled="disabled"
27
+ :content="codeConfig"
28
+ @submit="submitCodeBlockHandler"
29
+ ></CodeBlockEditor>
30
+ </div>
31
+ </template>
32
+
33
+ <script lang="ts" setup name="">
34
+ import { computed, inject, ref } from 'vue';
35
+ import { Edit, View } from '@element-plus/icons-vue';
36
+
37
+ import { createValues, FieldProps } from '@tmagic/form';
38
+ import type { CodeBlockContent, Id } from '@tmagic/schema';
39
+
40
+ import CodeBlockEditor from '@editor/components/CodeBlockEditor.vue';
41
+ import CodeParams from '@editor/components/CodeParams.vue';
42
+ import Icon from '@editor/components/Icon.vue';
43
+ import { useDataSourceMethod } from '@editor/hooks/use-data-source-method';
44
+ import type { CodeParamStatement, DataSourceMethodSelectConfig, Services } from '@editor/type';
45
+
46
+ defineOptions({
47
+ name: 'MEditorDataSourceMethodSelect',
48
+ });
49
+
50
+ const services = inject<Services>('services');
51
+ const emit = defineEmits(['change']);
52
+
53
+ const props = withDefaults(defineProps<FieldProps<DataSourceMethodSelectConfig>>(), {
54
+ disabled: false,
55
+ });
56
+
57
+ const dataSources = computed(() => services?.dataSourceService.get('dataSources'));
58
+
59
+ const getParamItemsConfig = ([dataSourceId, medthodName]: [Id, string] = ['', '']): CodeParamStatement[] => {
60
+ if (!dataSourceId) return [];
61
+
62
+ const paramStatements = dataSources.value
63
+ ?.find((item) => item.id === dataSourceId)
64
+ ?.methods?.find((item) => item.name === medthodName)?.params;
65
+
66
+ if (!paramStatements) return [];
67
+
68
+ return paramStatements.map((paramState: CodeParamStatement) => ({
69
+ labelWidth: '100px',
70
+ text: paramState.name,
71
+ ...paramState,
72
+ }));
73
+ };
74
+
75
+ const paramsConfig = ref<CodeParamStatement[]>(getParamItemsConfig(props.model.dataSourceMethod));
76
+
77
+ const setParamsConfig = (dataSourceMethod: [Id, string], formState: any = {}) => {
78
+ // 通过下拉框选择的codeId变化后修正model的值,避免写入其他codeId的params
79
+ paramsConfig.value = dataSourceMethod ? getParamItemsConfig(dataSourceMethod) : [];
80
+
81
+ if (paramsConfig.value.length) {
82
+ props.model.params = createValues(formState, paramsConfig.value, {}, props.model.params);
83
+ } else {
84
+ props.model.params = {};
85
+ }
86
+ };
87
+
88
+ const cascaderConfig = {
89
+ type: 'cascader',
90
+ text: '数据源方法',
91
+ name: props.name,
92
+ labelWidth: '80px',
93
+ options: () =>
94
+ dataSources.value
95
+ ?.filter((ds) => ds.methods?.length)
96
+ ?.map((ds) => ({
97
+ label: ds.title || ds.id,
98
+ value: ds.id,
99
+ children: ds.methods?.map((method) => ({
100
+ label: method.name,
101
+ value: method.name,
102
+ })),
103
+ })) || [],
104
+ onChange: (formState: any, dataSourceMethod: [Id, string]) => {
105
+ setParamsConfig(dataSourceMethod, formState);
106
+
107
+ return dataSourceMethod;
108
+ },
109
+ };
110
+
111
+ /**
112
+ * 参数值修改更新
113
+ */
114
+ const onChangeHandler = (value: any) => {
115
+ props.model.params = value.params;
116
+ emit('change', props.model);
117
+ };
118
+
119
+ const { codeBlockEditor, codeConfig, editCode, submitCode } = useDataSourceMethod();
120
+
121
+ const editCodeHandler = () => {
122
+ const [id, name] = props.model[props.name];
123
+
124
+ const dataSource = services?.dataSourceService.getDataSourceById(id);
125
+
126
+ if (!dataSource) return;
127
+
128
+ editCode(dataSource, name);
129
+
130
+ setParamsConfig([id, name]);
131
+ };
132
+
133
+ const submitCodeBlockHandler = (value: CodeBlockContent) => {
134
+ submitCode(value);
135
+ };
136
+ </script>