@tmagic/editor 1.4.8 → 1.4.10

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 (166) hide show
  1. package/dist/style.css +26 -0
  2. package/dist/tmagic-editor.js +3213 -2820
  3. package/dist/tmagic-editor.umd.cjs +3237 -2839
  4. package/package.json +14 -12
  5. package/src/Editor.vue +212 -0
  6. package/src/components/CodeBlockEditor.vue +268 -0
  7. package/src/components/CodeParams.vue +60 -0
  8. package/src/components/ContentMenu.vue +193 -0
  9. package/src/components/FloatingBox.vue +178 -0
  10. package/src/components/Icon.vue +27 -0
  11. package/src/components/Resizer.vue +23 -0
  12. package/src/components/ScrollBar.vue +151 -0
  13. package/src/components/ScrollViewer.vue +128 -0
  14. package/src/components/SearchInput.vue +37 -0
  15. package/src/components/SplitView.vue +186 -0
  16. package/src/components/ToolButton.vue +138 -0
  17. package/src/components/Tree.vue +71 -0
  18. package/src/components/TreeNode.vue +150 -0
  19. package/src/editorProps.ts +120 -0
  20. package/src/fields/Code.vue +50 -0
  21. package/src/fields/CodeLink.vue +80 -0
  22. package/src/fields/CodeSelect.vue +132 -0
  23. package/src/fields/CodeSelectCol.vue +139 -0
  24. package/src/fields/CondOpSelect.vue +87 -0
  25. package/src/fields/DataSourceFieldSelect/FieldSelect.vue +152 -0
  26. package/src/fields/DataSourceFieldSelect/Index.vue +168 -0
  27. package/src/fields/DataSourceFields.vue +329 -0
  28. package/src/fields/DataSourceInput.vue +339 -0
  29. package/src/fields/DataSourceMethodSelect.vue +153 -0
  30. package/src/fields/DataSourceMethods.vue +104 -0
  31. package/src/fields/DataSourceMocks.vue +255 -0
  32. package/src/fields/DataSourceSelect.vue +98 -0
  33. package/src/fields/DisplayConds.vue +145 -0
  34. package/src/fields/EventSelect.vue +375 -0
  35. package/src/fields/KeyValue.vue +137 -0
  36. package/src/fields/PageFragmentSelect.vue +63 -0
  37. package/src/fields/UISelect.vue +135 -0
  38. package/src/hooks/index.ts +24 -0
  39. package/src/hooks/use-code-block-edit.ts +83 -0
  40. package/src/hooks/use-data-source-edit.ts +46 -0
  41. package/src/hooks/use-data-source-method.ts +100 -0
  42. package/src/hooks/use-editor-content-height.ts +26 -0
  43. package/src/hooks/use-filter.ts +55 -0
  44. package/src/hooks/use-float-box.ts +76 -0
  45. package/src/hooks/use-getso.ts +35 -0
  46. package/src/hooks/use-next-float-box-position.ts +29 -0
  47. package/src/hooks/use-node-status.ts +48 -0
  48. package/src/hooks/use-stage.ts +129 -0
  49. package/src/hooks/use-window-rect.ts +20 -0
  50. package/src/icons/AppManageIcon.vue +15 -0
  51. package/src/icons/CenterIcon.vue +13 -0
  52. package/src/icons/CodeIcon.vue +28 -0
  53. package/src/icons/FolderMinusIcon.vue +22 -0
  54. package/src/icons/PinIcon.vue +25 -0
  55. package/src/icons/PinnedIcon.vue +25 -0
  56. package/src/index.ts +124 -0
  57. package/src/initService.ts +448 -0
  58. package/src/layouts/AddPageBox.vue +55 -0
  59. package/src/layouts/CodeEditor.vue +226 -0
  60. package/src/layouts/Framework.vue +165 -0
  61. package/src/layouts/NavMenu.vue +200 -0
  62. package/src/layouts/PropsPanel.vue +131 -0
  63. package/src/layouts/page-bar/AddButton.vue +48 -0
  64. package/src/layouts/page-bar/PageBar.vue +165 -0
  65. package/src/layouts/page-bar/PageBarScrollContainer.vue +192 -0
  66. package/src/layouts/page-bar/PageList.vue +55 -0
  67. package/src/layouts/page-bar/SwitchTypeButton.vue +45 -0
  68. package/src/layouts/sidebar/ComponentListPanel.vue +134 -0
  69. package/src/layouts/sidebar/Sidebar.vue +278 -0
  70. package/src/layouts/sidebar/code-block/CodeBlockList.vue +160 -0
  71. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +70 -0
  72. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +84 -0
  73. package/src/layouts/sidebar/data-source/DataSourceList.vue +172 -0
  74. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +106 -0
  75. package/src/layouts/sidebar/layer/LayerMenu.vue +128 -0
  76. package/src/layouts/sidebar/layer/LayerNodeTool.vue +32 -0
  77. package/src/layouts/sidebar/layer/LayerPanel.vue +119 -0
  78. package/src/layouts/sidebar/layer/use-click.ts +113 -0
  79. package/src/layouts/sidebar/layer/use-drag.ts +167 -0
  80. package/src/layouts/sidebar/layer/use-keybinding.ts +54 -0
  81. package/src/layouts/sidebar/layer/use-node-status.ts +114 -0
  82. package/src/layouts/workspace/Breadcrumb.vue +35 -0
  83. package/src/layouts/workspace/Workspace.vue +46 -0
  84. package/src/layouts/workspace/viewer/NodeListMenu.vue +115 -0
  85. package/src/layouts/workspace/viewer/Stage.vue +246 -0
  86. package/src/layouts/workspace/viewer/StageOverlay.vue +68 -0
  87. package/src/layouts/workspace/viewer/ViewerMenu.vue +145 -0
  88. package/src/services/BaseService.ts +230 -0
  89. package/src/services/codeBlock.ts +327 -0
  90. package/src/services/componentList.ts +58 -0
  91. package/src/services/dataSource.ts +216 -0
  92. package/src/services/dep.ts +152 -0
  93. package/src/services/editor.ts +1135 -0
  94. package/src/services/events.ts +93 -0
  95. package/src/services/history.ts +126 -0
  96. package/src/services/keybinding.ts +220 -0
  97. package/src/services/props.ts +286 -0
  98. package/src/services/stageOverlay.ts +212 -0
  99. package/src/services/storage.ts +155 -0
  100. package/src/services/ui.ts +157 -0
  101. package/src/shims-vue.d.ts +6 -0
  102. package/src/theme/breadcrumb.scss +6 -0
  103. package/src/theme/code-block.scss +6 -0
  104. package/src/theme/code-editor.scss +38 -0
  105. package/src/theme/common/var.scss +14 -0
  106. package/src/theme/component-list-panel.scss +95 -0
  107. package/src/theme/content-menu.scss +76 -0
  108. package/src/theme/data-source-field-select.scss +16 -0
  109. package/src/theme/data-source-field.scss +12 -0
  110. package/src/theme/data-source-fields.scss +13 -0
  111. package/src/theme/data-source-input.scss +18 -0
  112. package/src/theme/data-source-methods.scss +13 -0
  113. package/src/theme/data-source.scss +28 -0
  114. package/src/theme/event.scss +37 -0
  115. package/src/theme/floating-box.scss +32 -0
  116. package/src/theme/framework.scss +69 -0
  117. package/src/theme/icon.scss +12 -0
  118. package/src/theme/index.scss +10 -0
  119. package/src/theme/key-value.scss +20 -0
  120. package/src/theme/layer-panel.scss +26 -0
  121. package/src/theme/layout.scss +9 -0
  122. package/src/theme/nav-menu.scss +78 -0
  123. package/src/theme/page-bar.scss +102 -0
  124. package/src/theme/page-fragment-select.scss +14 -0
  125. package/src/theme/props-panel.scss +55 -0
  126. package/src/theme/resizer.scss +66 -0
  127. package/src/theme/ruler.scss +38 -0
  128. package/src/theme/search-input.scss +14 -0
  129. package/src/theme/sidebar.scss +79 -0
  130. package/src/theme/stage.scss +76 -0
  131. package/src/theme/theme.scss +28 -0
  132. package/src/theme/tree.scss +89 -0
  133. package/src/theme/workspace.scss +9 -0
  134. package/src/type.ts +780 -0
  135. package/src/utils/compose.ts +52 -0
  136. package/src/utils/config.ts +29 -0
  137. package/src/utils/content-menu.ts +95 -0
  138. package/src/utils/data-source/formConfigs/base.ts +30 -0
  139. package/src/utils/data-source/formConfigs/http.ts +60 -0
  140. package/src/utils/data-source/index.ts +249 -0
  141. package/src/utils/editor.ts +313 -0
  142. package/src/utils/idle-task.ts +72 -0
  143. package/src/utils/index.ts +24 -0
  144. package/src/utils/keybinding-config.ts +125 -0
  145. package/src/utils/logger.ts +47 -0
  146. package/src/utils/monaco-editor.ts +8 -0
  147. package/src/utils/operator.ts +106 -0
  148. package/src/utils/props.ts +407 -0
  149. package/src/utils/scroll-viewer.ts +165 -0
  150. package/src/utils/tree.ts +15 -0
  151. package/src/utils/undo-redo.ts +76 -0
  152. package/types/editorProps.d.ts +3 -1
  153. package/types/fields/CondOpSelect.vue.d.ts +17 -0
  154. package/types/fields/DataSourceFieldSelect/FieldSelect.vue.d.ts +36 -0
  155. package/types/fields/{DataSourceFieldSelect.vue.d.ts → DataSourceFieldSelect/Index.vue.d.ts} +1 -1
  156. package/types/fields/DisplayConds.vue.d.ts +32 -0
  157. package/types/index.d.ts +3 -1
  158. package/types/layouts/Framework.vue.d.ts +3 -1
  159. package/types/layouts/PropsPanel.vue.d.ts +21 -21
  160. package/types/layouts/page-bar/PageBar.vue.d.ts +6 -0
  161. package/types/layouts/page-bar/PageBarScrollContainer.vue.d.ts +3 -0
  162. package/types/layouts/page-bar/PageList.vue.d.ts +25 -0
  163. package/types/services/ui.d.ts +1 -0
  164. package/types/type.d.ts +30 -4
  165. package/types/utils/data-source/index.d.ts +1 -0
  166. package/types/utils/props.d.ts +12 -0
@@ -0,0 +1,50 @@
1
+ <template>
2
+ <MagicCodeEditor
3
+ :height="config.height"
4
+ :init-values="model[name]"
5
+ :language="config.language"
6
+ :options="{
7
+ ...config.options,
8
+ readOnly: disabled,
9
+ }"
10
+ :parse="config.parse"
11
+ @save="save"
12
+ ></MagicCodeEditor>
13
+ </template>
14
+
15
+ <script lang="ts" setup>
16
+ import type { FieldProps, FormItem } from '@tmagic/form';
17
+
18
+ import MagicCodeEditor from '@editor/layouts/CodeEditor.vue';
19
+
20
+ defineOptions({
21
+ name: 'MFieldsVsCode',
22
+ });
23
+
24
+ const emit = defineEmits<{
25
+ change: [value: string | any];
26
+ }>();
27
+
28
+ const props = withDefaults(
29
+ defineProps<
30
+ FieldProps<
31
+ {
32
+ language?: string;
33
+ options?: {
34
+ [key: string]: any;
35
+ };
36
+ height?: string;
37
+ parse?: boolean;
38
+ } & FormItem
39
+ >
40
+ >(),
41
+ {
42
+ disabled: false,
43
+ },
44
+ );
45
+
46
+ const save = (v: string | any) => {
47
+ props.model[props.name] = v;
48
+ emit('change', v);
49
+ };
50
+ </script>
@@ -0,0 +1,80 @@
1
+ <template>
2
+ <m-fields-link :config="formConfig" :model="modelValue" name="form" @change="changeHandler"></m-fields-link>
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ import { computed, reactive, watch } from 'vue';
7
+ import serialize from 'serialize-javascript';
8
+
9
+ import type { FieldProps, FormItem } from '@tmagic/form';
10
+
11
+ import { getConfig } from '@editor/utils/config';
12
+
13
+ defineOptions({
14
+ name: 'MFieldsCodeLink',
15
+ });
16
+
17
+ const props = defineProps<
18
+ FieldProps<
19
+ {
20
+ type: 'code-link';
21
+ formTitle?: string;
22
+ codeOptions?: Object;
23
+ } & FormItem
24
+ >
25
+ >();
26
+
27
+ const emit = defineEmits(['change']);
28
+
29
+ const formConfig = computed(() => {
30
+ const { codeOptions, ...config } = props.config;
31
+ return {
32
+ ...config,
33
+ text: '',
34
+ type: 'link',
35
+ form: [
36
+ {
37
+ name: props.name,
38
+ type: 'vs-code',
39
+ options: {
40
+ tabSize: 2,
41
+ ...(codeOptions || {}),
42
+ },
43
+ },
44
+ ],
45
+ };
46
+ });
47
+
48
+ const modelValue = reactive<{ form: Record<string, string> }>({
49
+ form: {
50
+ [props.name]: '',
51
+ },
52
+ });
53
+
54
+ watch(
55
+ () => props.model[props.name],
56
+ (value) => {
57
+ modelValue.form = {
58
+ [props.name]: serialize(value, {
59
+ space: 2,
60
+ unsafe: true,
61
+ }).replace(/"(\w+)":\s/g, '$1: '),
62
+ };
63
+ },
64
+ {
65
+ immediate: true,
66
+ },
67
+ );
68
+
69
+ const changeHandler = (v: Record<string, any>) => {
70
+ if (!props.name || !props.model) return;
71
+
72
+ try {
73
+ const parseDSL = getConfig('parseDSL');
74
+ props.model[props.name] = parseDSL(`(${v[props.name]})`);
75
+ emit('change', props.model[props.name]);
76
+ } catch (e) {
77
+ console.error(e);
78
+ }
79
+ };
80
+ </script>
@@ -0,0 +1,132 @@
1
+ <template>
2
+ <div class="m-fields-code-select" :class="config.className">
3
+ <TMagicCard>
4
+ <MContainer
5
+ :config="codeConfig"
6
+ :size="size"
7
+ :prop="prop"
8
+ :disabled="disabled"
9
+ :lastValues="lastValues"
10
+ :model="model[name]"
11
+ @change="changeHandler"
12
+ >
13
+ </MContainer>
14
+ </TMagicCard>
15
+ </div>
16
+ </template>
17
+
18
+ <script lang="ts" setup>
19
+ import { computed, inject, watch } from 'vue';
20
+ import { isEmpty } from 'lodash-es';
21
+
22
+ import { TMagicCard } from '@tmagic/design';
23
+ import type { FieldProps, FormItem } from '@tmagic/form';
24
+ import { FormState, MContainer } from '@tmagic/form';
25
+ import { HookCodeType, HookType } from '@tmagic/schema';
26
+
27
+ import type { Services } from '@editor/type';
28
+
29
+ defineOptions({
30
+ name: 'MFieldsCodeSelect',
31
+ });
32
+
33
+ const emit = defineEmits(['change']);
34
+
35
+ const services = inject<Services>('services');
36
+
37
+ const props = withDefaults(
38
+ defineProps<
39
+ FieldProps<
40
+ {
41
+ className?: string;
42
+ } & FormItem
43
+ >
44
+ >(),
45
+ {},
46
+ );
47
+
48
+ const codeConfig = computed(() => ({
49
+ type: 'group-list',
50
+ name: 'hookData',
51
+ enableToggleMode: false,
52
+ expandAll: true,
53
+ title: (mForm: FormState, { model, index }: any) => {
54
+ if (model.codeType === HookCodeType.DATA_SOURCE_METHOD) {
55
+ if (Array.isArray(model.codeId)) {
56
+ if (model.codeId.length < 2) {
57
+ return index;
58
+ }
59
+
60
+ const ds = services?.dataSourceService.getDataSourceById(model.codeId[0]);
61
+ return `${ds?.title} / ${model.codeId[1]}`;
62
+ }
63
+
64
+ return Array.isArray(model.codeId) ? model.codeId.join('/') : index;
65
+ }
66
+ return model.codeId || index;
67
+ },
68
+ items: [
69
+ {
70
+ type: 'row',
71
+ items: [
72
+ {
73
+ type: 'select',
74
+ name: 'codeType',
75
+ span: 8,
76
+ options: [
77
+ { value: HookCodeType.CODE, text: '代码块' },
78
+ { value: HookCodeType.DATA_SOURCE_METHOD, text: '数据源方法' },
79
+ ],
80
+ defaultValue: 'code',
81
+ onChange: (mForm: FormState, v: HookCodeType, { model }: any) => {
82
+ if (v === HookCodeType.DATA_SOURCE_METHOD) {
83
+ model.codeId = [];
84
+ } else {
85
+ model.codeId = '';
86
+ }
87
+
88
+ return v;
89
+ },
90
+ },
91
+ {
92
+ type: 'code-select-col',
93
+ name: 'codeId',
94
+ span: 16,
95
+ labelWidth: 0,
96
+ display: (mForm: FormState, { model }: any) => model.codeType !== HookCodeType.DATA_SOURCE_METHOD,
97
+ notEditable: () => !services?.codeBlockService.getEditStatus(),
98
+ },
99
+ {
100
+ type: 'data-source-method-select',
101
+ name: 'codeId',
102
+ span: 16,
103
+ labelWidth: 0,
104
+ display: (mForm: FormState, { model }: any) => model.codeType === HookCodeType.DATA_SOURCE_METHOD,
105
+ notEditable: () => !services?.dataSourceService.get('editable'),
106
+ },
107
+ ],
108
+ },
109
+ ],
110
+ }));
111
+
112
+ watch(
113
+ () => props.model[props.name],
114
+ (value) => {
115
+ // 兼容旧的数据结构
116
+ if (isEmpty(value)) {
117
+ // 空值或者空数组
118
+ props.model[props.name] = {
119
+ hookType: HookType.CODE,
120
+ hookData: [],
121
+ };
122
+ }
123
+ },
124
+ {
125
+ immediate: true,
126
+ },
127
+ );
128
+
129
+ const changeHandler = async () => {
130
+ emit('change', props.model[props.name]);
131
+ };
132
+ </script>
@@ -0,0 +1,139 @@
1
+ <template>
2
+ <div class="m-fields-code-select-col">
3
+ <div class="code-select-container">
4
+ <!-- 代码块下拉框 -->
5
+ <MContainer
6
+ class="select"
7
+ :config="selectConfig"
8
+ :model="model"
9
+ :size="size"
10
+ @change="onParamsChangeHandler"
11
+ ></MContainer>
12
+
13
+ <!-- 查看/编辑按钮 -->
14
+ <TMagicButton
15
+ v-if="model[name] && hasCodeBlockSidePanel"
16
+ class="m-fields-select-action-button"
17
+ :size="size"
18
+ @click="editCode(model[name])"
19
+ >
20
+ <MIcon :icon="!notEditable ? Edit : View"></MIcon>
21
+ </TMagicButton>
22
+ </div>
23
+
24
+ <!-- 参数填写框 -->
25
+ <CodeParams
26
+ v-if="paramsConfig.length"
27
+ name="params"
28
+ :key="model[name]"
29
+ :model="model"
30
+ :size="size"
31
+ :params-config="paramsConfig"
32
+ @change="onParamsChangeHandler"
33
+ ></CodeParams>
34
+ </div>
35
+ </template>
36
+
37
+ <script lang="ts" setup>
38
+ import { computed, inject, ref, watch } from 'vue';
39
+ import { Edit, View } from '@element-plus/icons-vue';
40
+ import { isEmpty, map } from 'lodash-es';
41
+
42
+ import { TMagicButton } from '@tmagic/design';
43
+ import { createValues, type FieldProps, filterFunction, type FormState, MContainer } from '@tmagic/form';
44
+ import type { Id } from '@tmagic/schema';
45
+
46
+ import CodeParams from '@editor/components/CodeParams.vue';
47
+ import MIcon from '@editor/components/Icon.vue';
48
+ import type { CodeParamStatement, CodeSelectColConfig, EventBus, Services } from '@editor/type';
49
+ import { SideItemKey } from '@editor/type';
50
+
51
+ defineOptions({
52
+ name: 'MFieldsCodeSelectCol',
53
+ });
54
+
55
+ const mForm = inject<FormState | undefined>('mForm');
56
+ const services = inject<Services>('services');
57
+ const eventBus = inject<EventBus>('eventBus');
58
+ const emit = defineEmits(['change']);
59
+
60
+ const props = withDefaults(defineProps<FieldProps<CodeSelectColConfig>>(), {
61
+ disabled: false,
62
+ });
63
+
64
+ const notEditable = computed(() => filterFunction(mForm, props.config.notEditable, props));
65
+
66
+ const hasCodeBlockSidePanel = computed(() =>
67
+ (services?.uiService.get('sideBarItems') || []).find((item) => item.$key === SideItemKey.CODE_BLOCK),
68
+ );
69
+
70
+ /**
71
+ * 根据代码块id获取代码块参数配置
72
+ * @param codeId 代码块ID
73
+ */
74
+ const getParamItemsConfig = (codeId?: Id): CodeParamStatement[] => {
75
+ if (!codeDsl.value || !codeId) return [];
76
+
77
+ const paramStatements = codeDsl.value[codeId]?.params;
78
+
79
+ if (isEmpty(paramStatements)) return [];
80
+
81
+ return paramStatements.map((paramState: CodeParamStatement) => ({
82
+ labelWidth: '100px',
83
+ text: paramState.name,
84
+ ...paramState,
85
+ }));
86
+ };
87
+
88
+ const codeDsl = computed(() => services?.codeBlockService.getCodeDsl());
89
+ const paramsConfig = ref<CodeParamStatement[]>(getParamItemsConfig(props.model[props.name]));
90
+
91
+ watch(
92
+ () => props.model[props.name],
93
+ (v, preV) => {
94
+ if (v !== preV) {
95
+ paramsConfig.value = getParamItemsConfig(v);
96
+ }
97
+ },
98
+ );
99
+
100
+ const selectConfig = {
101
+ type: 'select',
102
+ name: props.name,
103
+ disable: props.disabled,
104
+ options: () => {
105
+ if (codeDsl.value) {
106
+ return map(codeDsl.value, (value, key) => ({
107
+ text: `${value.name}(${key})`,
108
+ label: `${value.name}(${key})`,
109
+ value: key,
110
+ }));
111
+ }
112
+ return [];
113
+ },
114
+ onChange: (formState: any, codeId: Id, { model }: any) => {
115
+ // 通过下拉框选择的codeId变化后修正model的值,避免写入其他codeId的params
116
+ paramsConfig.value = getParamItemsConfig(codeId);
117
+
118
+ if (paramsConfig.value.length) {
119
+ model.params = createValues(formState, paramsConfig.value, {}, model.params);
120
+ } else {
121
+ model.params = {};
122
+ }
123
+
124
+ return codeId;
125
+ },
126
+ };
127
+
128
+ /**
129
+ * 参数值修改更新
130
+ */
131
+ const onParamsChangeHandler = (value: any) => {
132
+ props.model.params = value.params;
133
+ emit('change', props.model);
134
+ };
135
+
136
+ const editCode = (id: string) => {
137
+ eventBus?.emit('edit-code', id);
138
+ };
139
+ </script>
@@ -0,0 +1,87 @@
1
+ <template>
2
+ <TMagicSelect
3
+ v-model="model[name]"
4
+ clearable
5
+ filterable
6
+ :size="size"
7
+ :disabled="disabled"
8
+ @change="fieldChangeHandler"
9
+ >
10
+ <component
11
+ v-for="option in options"
12
+ class="tmagic-design-option"
13
+ :key="option.value"
14
+ :is="optionComponent?.component || 'el-option'"
15
+ v-bind="
16
+ optionComponent?.props({
17
+ label: option.text,
18
+ value: option.value,
19
+ }) || {
20
+ label: option.text,
21
+ value: option.value,
22
+ }
23
+ "
24
+ >
25
+ </component>
26
+ </TMagicSelect>
27
+ </template>
28
+
29
+ <script setup lang="ts">
30
+ import { computed, inject } from 'vue';
31
+
32
+ import { getConfig as getDesignConfig, TMagicSelect } from '@tmagic/design';
33
+ import type { FieldProps } from '@tmagic/form';
34
+
35
+ import type { CondOpSelectConfig, Services } from '@editor/type';
36
+ import { arrayOptions, eqOptions, numberOptions } from '@editor/utils';
37
+
38
+ defineOptions({
39
+ name: 'MFieldsCondOpSelect',
40
+ });
41
+
42
+ const emit = defineEmits(['change']);
43
+ const { dataSourceService } = inject<Services>('services') || {};
44
+
45
+ const props = defineProps<FieldProps<CondOpSelectConfig>>();
46
+
47
+ const optionComponent = getDesignConfig('components')?.option;
48
+
49
+ const options = computed(() => {
50
+ const [id, ...fieldNames] = [...(props.config.parentFields || []), ...props.model.field];
51
+
52
+ const ds = dataSourceService?.getDataSourceById(id);
53
+
54
+ let fields = ds?.fields || [];
55
+ let type = '';
56
+ (fieldNames || []).forEach((fieldName: string) => {
57
+ const field = fields.find((f) => f.name === fieldName);
58
+ fields = field?.fields || [];
59
+ type = field?.type || '';
60
+ });
61
+
62
+ if (type === 'array') {
63
+ return arrayOptions;
64
+ }
65
+
66
+ if (type === 'boolean') {
67
+ return [
68
+ { text: '是', value: 'is' },
69
+ { text: '不是', value: 'not' },
70
+ ];
71
+ }
72
+
73
+ if (type === 'number') {
74
+ return [...eqOptions, ...numberOptions];
75
+ }
76
+
77
+ if (type === 'string') {
78
+ return [...arrayOptions, ...eqOptions];
79
+ }
80
+
81
+ return [...arrayOptions, ...eqOptions, ...numberOptions];
82
+ });
83
+
84
+ const fieldChangeHandler = (v: string[]) => {
85
+ emit('change', v);
86
+ };
87
+ </script>
@@ -0,0 +1,152 @@
1
+ <template>
2
+ <div class="m-editor-data-source-field-select">
3
+ <TMagicSelect
4
+ :model-value="selectDataSourceId"
5
+ clearable
6
+ filterable
7
+ :size="size"
8
+ :disabled="disabled"
9
+ @change="dsChangeHandler"
10
+ >
11
+ <component
12
+ v-for="option in dataSourcesOptions"
13
+ class="tmagic-design-option"
14
+ :key="option.value"
15
+ :is="optionComponent?.component || 'el-option'"
16
+ v-bind="
17
+ optionComponent?.props({
18
+ label: option.text,
19
+ value: option.value,
20
+ disabled: option.disabled,
21
+ }) || {
22
+ label: option.text,
23
+ value: option.value,
24
+ disabled: option.disabled,
25
+ }
26
+ "
27
+ >
28
+ </component>
29
+ </TMagicSelect>
30
+
31
+ <TMagicCascader
32
+ :model-value="selectFieldsId"
33
+ clearable
34
+ filterable
35
+ :size="size"
36
+ :disabled="disabled"
37
+ :options="fieldsOptions"
38
+ :props="{
39
+ checkStrictly,
40
+ }"
41
+ @change="fieldChangeHandler"
42
+ ></TMagicCascader>
43
+
44
+ <TMagicButton
45
+ v-if="selectDataSourceId && hasDataSourceSidePanel"
46
+ class="m-fields-select-action-button"
47
+ :size="size"
48
+ @click="editHandler(selectDataSourceId)"
49
+ ><MIcon :icon="!notEditable ? Edit : View"></MIcon
50
+ ></TMagicButton>
51
+ </div>
52
+ </template>
53
+
54
+ <script lang="ts" setup>
55
+ import { computed, inject, ref, watch } from 'vue';
56
+ import { Edit, View } from '@element-plus/icons-vue';
57
+
58
+ import { getConfig as getDesignConfig, TMagicButton, TMagicCascader, TMagicSelect } from '@tmagic/design';
59
+ import { type FilterFunction, filterFunction, type FormState, type SelectOption } from '@tmagic/form';
60
+ import { DataSourceFieldType } from '@tmagic/schema';
61
+ import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX } from '@tmagic/utils';
62
+
63
+ import MIcon from '@editor/components/Icon.vue';
64
+ import { type EventBus, type Services, SideItemKey } from '@editor/type';
65
+ import { getCascaderOptionsFromFields, removeDataSourceFieldPrefix } from '@editor/utils';
66
+
67
+ const props = defineProps<{
68
+ /**
69
+ * 是否要编译成数据源的data。
70
+ * key: 不编译,就是要数据源id和field name;
71
+ * value: 要编译(数据源data[`${filed}`])
72
+ * */
73
+ value?: 'key' | 'value';
74
+ disabled?: boolean;
75
+ checkStrictly?: boolean;
76
+ size?: 'large' | 'default' | 'small';
77
+ dataSourceFieldType?: DataSourceFieldType[];
78
+ /** 是否可以编辑数据源,disable表示的是是否可以选择数据源 */
79
+ notEditable?: boolean | FilterFunction;
80
+ }>();
81
+
82
+ const emit = defineEmits<{
83
+ change: [v: string[]];
84
+ }>();
85
+
86
+ const modelValue = defineModel<string[] | any>('modelValue', { default: [] });
87
+
88
+ const optionComponent = getDesignConfig('components')?.option;
89
+
90
+ const services = inject<Services>('services');
91
+ const mForm = inject<FormState | undefined>('mForm');
92
+ const eventBus = inject<EventBus>('eventBus');
93
+
94
+ const dataSources = computed(() => services?.dataSourceService.get('dataSources') || []);
95
+
96
+ const valueIsKey = computed(() => props.value === 'key');
97
+ const notEditable = computed(() => filterFunction(mForm, props.notEditable, props));
98
+
99
+ const dataSourcesOptions = computed<SelectOption[]>(() =>
100
+ dataSources.value.map((ds) => ({
101
+ text: ds.title || ds.id,
102
+ value: valueIsKey.value ? ds.id : `${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}${ds.id}`,
103
+ })),
104
+ );
105
+
106
+ const selectDataSourceId = ref('');
107
+
108
+ const selectFieldsId = ref<string[]>([]);
109
+
110
+ watch(
111
+ modelValue,
112
+ (value) => {
113
+ if (Array.isArray(value)) {
114
+ const [dsId, ...fields] = value;
115
+ selectDataSourceId.value = dsId;
116
+ selectFieldsId.value = fields;
117
+ } else {
118
+ selectDataSourceId.value = '';
119
+ selectFieldsId.value = [];
120
+ }
121
+ },
122
+ {
123
+ immediate: true,
124
+ },
125
+ );
126
+
127
+ const fieldsOptions = computed(() => {
128
+ const ds = dataSources.value.find((ds) => ds.id === removeDataSourceFieldPrefix(selectDataSourceId.value));
129
+
130
+ if (!ds) return [];
131
+
132
+ return getCascaderOptionsFromFields(ds.fields, props.dataSourceFieldType);
133
+ });
134
+
135
+ const dsChangeHandler = (v: string) => {
136
+ modelValue.value = [v];
137
+ emit('change', modelValue.value);
138
+ };
139
+
140
+ const fieldChangeHandler = (v: string[] = []) => {
141
+ modelValue.value = [selectDataSourceId.value, ...v];
142
+ emit('change', modelValue.value);
143
+ };
144
+
145
+ const hasDataSourceSidePanel = computed(() =>
146
+ (services?.uiService.get('sideBarItems') || []).find((item) => item.$key === SideItemKey.DATA_SOURCE),
147
+ );
148
+
149
+ const editHandler = (id: string) => {
150
+ eventBus?.emit('edit-data-source', removeDataSourceFieldPrefix(id));
151
+ };
152
+ </script>