@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.
- package/dist/style.css +26 -0
- package/dist/tmagic-editor.js +3213 -2820
- package/dist/tmagic-editor.umd.cjs +3237 -2839
- package/package.json +14 -12
- package/src/Editor.vue +212 -0
- package/src/components/CodeBlockEditor.vue +268 -0
- package/src/components/CodeParams.vue +60 -0
- package/src/components/ContentMenu.vue +193 -0
- package/src/components/FloatingBox.vue +178 -0
- package/src/components/Icon.vue +27 -0
- package/src/components/Resizer.vue +23 -0
- package/src/components/ScrollBar.vue +151 -0
- package/src/components/ScrollViewer.vue +128 -0
- package/src/components/SearchInput.vue +37 -0
- package/src/components/SplitView.vue +186 -0
- package/src/components/ToolButton.vue +138 -0
- package/src/components/Tree.vue +71 -0
- package/src/components/TreeNode.vue +150 -0
- package/src/editorProps.ts +120 -0
- package/src/fields/Code.vue +50 -0
- package/src/fields/CodeLink.vue +80 -0
- package/src/fields/CodeSelect.vue +132 -0
- package/src/fields/CodeSelectCol.vue +139 -0
- package/src/fields/CondOpSelect.vue +87 -0
- package/src/fields/DataSourceFieldSelect/FieldSelect.vue +152 -0
- package/src/fields/DataSourceFieldSelect/Index.vue +168 -0
- package/src/fields/DataSourceFields.vue +329 -0
- package/src/fields/DataSourceInput.vue +339 -0
- package/src/fields/DataSourceMethodSelect.vue +153 -0
- package/src/fields/DataSourceMethods.vue +104 -0
- package/src/fields/DataSourceMocks.vue +255 -0
- package/src/fields/DataSourceSelect.vue +98 -0
- package/src/fields/DisplayConds.vue +145 -0
- package/src/fields/EventSelect.vue +375 -0
- package/src/fields/KeyValue.vue +137 -0
- package/src/fields/PageFragmentSelect.vue +63 -0
- package/src/fields/UISelect.vue +135 -0
- package/src/hooks/index.ts +24 -0
- package/src/hooks/use-code-block-edit.ts +83 -0
- package/src/hooks/use-data-source-edit.ts +46 -0
- package/src/hooks/use-data-source-method.ts +100 -0
- package/src/hooks/use-editor-content-height.ts +26 -0
- package/src/hooks/use-filter.ts +55 -0
- package/src/hooks/use-float-box.ts +76 -0
- package/src/hooks/use-getso.ts +35 -0
- package/src/hooks/use-next-float-box-position.ts +29 -0
- package/src/hooks/use-node-status.ts +48 -0
- package/src/hooks/use-stage.ts +129 -0
- package/src/hooks/use-window-rect.ts +20 -0
- package/src/icons/AppManageIcon.vue +15 -0
- package/src/icons/CenterIcon.vue +13 -0
- package/src/icons/CodeIcon.vue +28 -0
- package/src/icons/FolderMinusIcon.vue +22 -0
- package/src/icons/PinIcon.vue +25 -0
- package/src/icons/PinnedIcon.vue +25 -0
- package/src/index.ts +124 -0
- package/src/initService.ts +448 -0
- package/src/layouts/AddPageBox.vue +55 -0
- package/src/layouts/CodeEditor.vue +226 -0
- package/src/layouts/Framework.vue +165 -0
- package/src/layouts/NavMenu.vue +200 -0
- package/src/layouts/PropsPanel.vue +131 -0
- package/src/layouts/page-bar/AddButton.vue +48 -0
- package/src/layouts/page-bar/PageBar.vue +165 -0
- package/src/layouts/page-bar/PageBarScrollContainer.vue +192 -0
- package/src/layouts/page-bar/PageList.vue +55 -0
- package/src/layouts/page-bar/SwitchTypeButton.vue +45 -0
- package/src/layouts/sidebar/ComponentListPanel.vue +134 -0
- package/src/layouts/sidebar/Sidebar.vue +278 -0
- package/src/layouts/sidebar/code-block/CodeBlockList.vue +160 -0
- package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +70 -0
- package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +84 -0
- package/src/layouts/sidebar/data-source/DataSourceList.vue +172 -0
- package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +106 -0
- package/src/layouts/sidebar/layer/LayerMenu.vue +128 -0
- package/src/layouts/sidebar/layer/LayerNodeTool.vue +32 -0
- package/src/layouts/sidebar/layer/LayerPanel.vue +119 -0
- package/src/layouts/sidebar/layer/use-click.ts +113 -0
- package/src/layouts/sidebar/layer/use-drag.ts +167 -0
- package/src/layouts/sidebar/layer/use-keybinding.ts +54 -0
- package/src/layouts/sidebar/layer/use-node-status.ts +114 -0
- package/src/layouts/workspace/Breadcrumb.vue +35 -0
- package/src/layouts/workspace/Workspace.vue +46 -0
- package/src/layouts/workspace/viewer/NodeListMenu.vue +115 -0
- package/src/layouts/workspace/viewer/Stage.vue +246 -0
- package/src/layouts/workspace/viewer/StageOverlay.vue +68 -0
- package/src/layouts/workspace/viewer/ViewerMenu.vue +145 -0
- package/src/services/BaseService.ts +230 -0
- package/src/services/codeBlock.ts +327 -0
- package/src/services/componentList.ts +58 -0
- package/src/services/dataSource.ts +216 -0
- package/src/services/dep.ts +152 -0
- package/src/services/editor.ts +1135 -0
- package/src/services/events.ts +93 -0
- package/src/services/history.ts +126 -0
- package/src/services/keybinding.ts +220 -0
- package/src/services/props.ts +286 -0
- package/src/services/stageOverlay.ts +212 -0
- package/src/services/storage.ts +155 -0
- package/src/services/ui.ts +157 -0
- package/src/shims-vue.d.ts +6 -0
- package/src/theme/breadcrumb.scss +6 -0
- package/src/theme/code-block.scss +6 -0
- package/src/theme/code-editor.scss +38 -0
- package/src/theme/common/var.scss +14 -0
- package/src/theme/component-list-panel.scss +95 -0
- package/src/theme/content-menu.scss +76 -0
- package/src/theme/data-source-field-select.scss +16 -0
- package/src/theme/data-source-field.scss +12 -0
- package/src/theme/data-source-fields.scss +13 -0
- package/src/theme/data-source-input.scss +18 -0
- package/src/theme/data-source-methods.scss +13 -0
- package/src/theme/data-source.scss +28 -0
- package/src/theme/event.scss +37 -0
- package/src/theme/floating-box.scss +32 -0
- package/src/theme/framework.scss +69 -0
- package/src/theme/icon.scss +12 -0
- package/src/theme/index.scss +10 -0
- package/src/theme/key-value.scss +20 -0
- package/src/theme/layer-panel.scss +26 -0
- package/src/theme/layout.scss +9 -0
- package/src/theme/nav-menu.scss +78 -0
- package/src/theme/page-bar.scss +102 -0
- package/src/theme/page-fragment-select.scss +14 -0
- package/src/theme/props-panel.scss +55 -0
- package/src/theme/resizer.scss +66 -0
- package/src/theme/ruler.scss +38 -0
- package/src/theme/search-input.scss +14 -0
- package/src/theme/sidebar.scss +79 -0
- package/src/theme/stage.scss +76 -0
- package/src/theme/theme.scss +28 -0
- package/src/theme/tree.scss +89 -0
- package/src/theme/workspace.scss +9 -0
- package/src/type.ts +780 -0
- package/src/utils/compose.ts +52 -0
- package/src/utils/config.ts +29 -0
- package/src/utils/content-menu.ts +95 -0
- package/src/utils/data-source/formConfigs/base.ts +30 -0
- package/src/utils/data-source/formConfigs/http.ts +60 -0
- package/src/utils/data-source/index.ts +249 -0
- package/src/utils/editor.ts +313 -0
- package/src/utils/idle-task.ts +72 -0
- package/src/utils/index.ts +24 -0
- package/src/utils/keybinding-config.ts +125 -0
- package/src/utils/logger.ts +47 -0
- package/src/utils/monaco-editor.ts +8 -0
- package/src/utils/operator.ts +106 -0
- package/src/utils/props.ts +407 -0
- package/src/utils/scroll-viewer.ts +165 -0
- package/src/utils/tree.ts +15 -0
- package/src/utils/undo-redo.ts +76 -0
- package/types/editorProps.d.ts +3 -1
- package/types/fields/CondOpSelect.vue.d.ts +17 -0
- package/types/fields/DataSourceFieldSelect/FieldSelect.vue.d.ts +36 -0
- package/types/fields/{DataSourceFieldSelect.vue.d.ts → DataSourceFieldSelect/Index.vue.d.ts} +1 -1
- package/types/fields/DisplayConds.vue.d.ts +32 -0
- package/types/index.d.ts +3 -1
- package/types/layouts/Framework.vue.d.ts +3 -1
- package/types/layouts/PropsPanel.vue.d.ts +21 -21
- package/types/layouts/page-bar/PageBar.vue.d.ts +6 -0
- package/types/layouts/page-bar/PageBarScrollContainer.vue.d.ts +3 -0
- package/types/layouts/page-bar/PageList.vue.d.ts +25 -0
- package/types/services/ui.d.ts +1 -0
- package/types/type.d.ts +30 -4
- package/types/utils/data-source/index.d.ts +1 -0
- package/types/utils/props.d.ts +12 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {Array} middleware
|
|
3
|
+
* @return {Function}
|
|
4
|
+
*/
|
|
5
|
+
export const compose = (middleware: Function[], isAsync: boolean) => {
|
|
6
|
+
if (!Array.isArray(middleware)) throw new TypeError('Middleware 必须是一个数组!');
|
|
7
|
+
for (const fn of middleware) {
|
|
8
|
+
if (typeof fn !== 'function') throw new TypeError('Middleware 必须由函数组成!');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {Object} args
|
|
13
|
+
* @return {Promise}
|
|
14
|
+
* @api public
|
|
15
|
+
*/
|
|
16
|
+
return (args: any[], next?: Function) => {
|
|
17
|
+
// last called middleware #
|
|
18
|
+
let index = -1;
|
|
19
|
+
return dispatch(0);
|
|
20
|
+
function dispatch(i: number): Promise<void> | void {
|
|
21
|
+
if (i <= index) {
|
|
22
|
+
const error = new Error('next() 被多次调用');
|
|
23
|
+
if (isAsync) {
|
|
24
|
+
return Promise.reject(error);
|
|
25
|
+
}
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
index = i;
|
|
29
|
+
let fn = middleware[i];
|
|
30
|
+
if (i === middleware.length && next) fn = next;
|
|
31
|
+
if (!fn) {
|
|
32
|
+
if (isAsync) {
|
|
33
|
+
return Promise.resolve();
|
|
34
|
+
}
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (isAsync) {
|
|
39
|
+
try {
|
|
40
|
+
return Promise.resolve(fn(...args, dispatch.bind(null, i + 1)));
|
|
41
|
+
} catch (err) {
|
|
42
|
+
return Promise.reject(err);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
return fn(...args, dispatch.bind(null, i + 1));
|
|
47
|
+
} catch (err) {
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { InstallOptions } from '@editor/type';
|
|
20
|
+
|
|
21
|
+
let $TMAGIC_EDITOR: InstallOptions = {} as any;
|
|
22
|
+
|
|
23
|
+
const setConfig = (option: InstallOptions): void => {
|
|
24
|
+
$TMAGIC_EDITOR = option;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const getConfig = <K extends keyof InstallOptions>(key: K): InstallOptions[K] => $TMAGIC_EDITOR[key];
|
|
28
|
+
|
|
29
|
+
export { getConfig, setConfig };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { computed, markRaw, Ref } from 'vue';
|
|
2
|
+
import { CopyDocument, Delete, DocumentCopy } from '@element-plus/icons-vue';
|
|
3
|
+
|
|
4
|
+
import { Id, MContainer, NodeType } from '@tmagic/schema';
|
|
5
|
+
import { calcValueByFontsize, isPage, isPageFragment } from '@tmagic/utils';
|
|
6
|
+
|
|
7
|
+
import ContentMenu from '@editor/components/ContentMenu.vue';
|
|
8
|
+
import type { MenuButton, Services } from '@editor/type';
|
|
9
|
+
|
|
10
|
+
import { COPY_STORAGE_KEY } from './editor';
|
|
11
|
+
|
|
12
|
+
export const useDeleteMenu = (): MenuButton => ({
|
|
13
|
+
type: 'button',
|
|
14
|
+
text: '删除',
|
|
15
|
+
icon: Delete,
|
|
16
|
+
display: (services) => {
|
|
17
|
+
const node = services?.editorService?.get('node');
|
|
18
|
+
return node?.type !== NodeType.ROOT && !isPage(node) && !isPageFragment(node);
|
|
19
|
+
},
|
|
20
|
+
handler: (services) => {
|
|
21
|
+
const nodes = services?.editorService?.get('nodes');
|
|
22
|
+
nodes && services?.editorService?.remove(nodes);
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export const useCopyMenu = (): MenuButton => ({
|
|
27
|
+
type: 'button',
|
|
28
|
+
text: '复制',
|
|
29
|
+
icon: markRaw(CopyDocument),
|
|
30
|
+
handler: (services) => {
|
|
31
|
+
const nodes = services?.editorService?.get('nodes');
|
|
32
|
+
nodes && services?.editorService?.copy(nodes);
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const usePasteMenu = (menu?: Ref<InstanceType<typeof ContentMenu> | undefined>): MenuButton => ({
|
|
37
|
+
type: 'button',
|
|
38
|
+
text: '粘贴',
|
|
39
|
+
icon: markRaw(DocumentCopy),
|
|
40
|
+
display: (services) => !!services?.storageService?.getItem(COPY_STORAGE_KEY),
|
|
41
|
+
handler: (services) => {
|
|
42
|
+
const nodes = services?.editorService?.get('nodes');
|
|
43
|
+
if (!nodes || nodes.length === 0) return;
|
|
44
|
+
|
|
45
|
+
if (menu?.value?.$el) {
|
|
46
|
+
const stage = services?.editorService?.get('stage');
|
|
47
|
+
const rect = menu.value.$el.getBoundingClientRect();
|
|
48
|
+
const parentRect = stage?.container?.getBoundingClientRect();
|
|
49
|
+
const initialLeft =
|
|
50
|
+
calcValueByFontsize(stage?.renderer.getDocument(), (rect.left || 0) - (parentRect?.left || 0)) /
|
|
51
|
+
services.uiService.get('zoom');
|
|
52
|
+
const initialTop =
|
|
53
|
+
calcValueByFontsize(stage?.renderer.getDocument(), (rect.top || 0) - (parentRect?.top || 0)) /
|
|
54
|
+
services.uiService.get('zoom');
|
|
55
|
+
services?.editorService?.paste({ left: initialLeft, top: initialTop });
|
|
56
|
+
} else {
|
|
57
|
+
services?.editorService?.paste();
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const moveTo = (id: Id, services?: Services) => {
|
|
63
|
+
if (!services?.editorService) return;
|
|
64
|
+
|
|
65
|
+
const nodes = services.editorService.get('nodes') || [];
|
|
66
|
+
const parent = services.editorService.getNodeById(id) as MContainer;
|
|
67
|
+
|
|
68
|
+
if (!parent) return;
|
|
69
|
+
|
|
70
|
+
services?.editorService.add(nodes, parent);
|
|
71
|
+
services?.editorService.remove(nodes);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const useMoveToMenu = (services?: Services): MenuButton => {
|
|
75
|
+
const root = computed(() => services?.editorService?.get('root'));
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
type: 'button',
|
|
79
|
+
text: '移动至',
|
|
80
|
+
display: (services) => {
|
|
81
|
+
const node = services?.editorService?.get('node');
|
|
82
|
+
const pageLength = services?.editorService?.get('pageLength') || 0;
|
|
83
|
+
return !isPage(node) && pageLength > 1;
|
|
84
|
+
},
|
|
85
|
+
items: (root.value?.items || [])
|
|
86
|
+
.filter((page) => page.id !== services?.editorService?.get('page')?.id)
|
|
87
|
+
.map((page) => ({
|
|
88
|
+
text: `${page.name}(${page.id})`,
|
|
89
|
+
type: 'button',
|
|
90
|
+
handler: (services?: Services) => {
|
|
91
|
+
moveTo(page.id, services);
|
|
92
|
+
},
|
|
93
|
+
})),
|
|
94
|
+
};
|
|
95
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { FormConfig } from '@tmagic/form';
|
|
2
|
+
|
|
3
|
+
export default function (): FormConfig {
|
|
4
|
+
return [
|
|
5
|
+
{
|
|
6
|
+
name: 'id',
|
|
7
|
+
type: 'hidden',
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
name: 'type',
|
|
11
|
+
text: '类型',
|
|
12
|
+
type: 'hidden',
|
|
13
|
+
defaultValue: 'base',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'title',
|
|
17
|
+
text: '名称',
|
|
18
|
+
rules: [
|
|
19
|
+
{
|
|
20
|
+
required: true,
|
|
21
|
+
message: '请输入名称',
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'description',
|
|
27
|
+
text: '描述',
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { FormConfig } from '@tmagic/form';
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
{
|
|
5
|
+
name: 'autoFetch',
|
|
6
|
+
text: '自动请求',
|
|
7
|
+
type: 'switch',
|
|
8
|
+
defaultValue: true,
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
name: 'responseOptions',
|
|
12
|
+
items: [
|
|
13
|
+
{
|
|
14
|
+
name: 'dataPath',
|
|
15
|
+
text: '数据路径',
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
type: 'fieldset',
|
|
21
|
+
name: 'options',
|
|
22
|
+
legend: 'HTTP 配置',
|
|
23
|
+
items: [
|
|
24
|
+
{
|
|
25
|
+
name: 'url',
|
|
26
|
+
text: 'URL',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'method',
|
|
30
|
+
text: 'Method',
|
|
31
|
+
type: 'select',
|
|
32
|
+
options: [
|
|
33
|
+
{ text: 'GET', value: 'GET' },
|
|
34
|
+
{ text: 'POST', value: 'POST' },
|
|
35
|
+
{ text: 'PUT', value: 'PUT' },
|
|
36
|
+
{ text: 'DELETE', value: 'DELETE' },
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'params',
|
|
41
|
+
type: 'key-value',
|
|
42
|
+
defaultValue: {},
|
|
43
|
+
text: '参数',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'data',
|
|
47
|
+
type: 'key-value',
|
|
48
|
+
defaultValue: {},
|
|
49
|
+
advanced: true,
|
|
50
|
+
text: '请求体',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'headers',
|
|
54
|
+
type: 'key-value',
|
|
55
|
+
defaultValue: {},
|
|
56
|
+
text: '请求头',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
] as FormConfig;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { CascaderOption, FormConfig, FormState } from '@tmagic/form';
|
|
2
|
+
import { DataSchema, DataSourceFieldType, DataSourceSchema } from '@tmagic/schema';
|
|
3
|
+
import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, isNumber } from '@tmagic/utils';
|
|
4
|
+
|
|
5
|
+
import BaseFormConfig from './formConfigs/base';
|
|
6
|
+
import HttpFormConfig from './formConfigs/http';
|
|
7
|
+
|
|
8
|
+
const fillConfig = (config: FormConfig): FormConfig => [
|
|
9
|
+
...BaseFormConfig(),
|
|
10
|
+
...config,
|
|
11
|
+
{
|
|
12
|
+
type: 'tab',
|
|
13
|
+
items: [
|
|
14
|
+
{
|
|
15
|
+
title: '数据定义',
|
|
16
|
+
items: [
|
|
17
|
+
{
|
|
18
|
+
name: 'fields',
|
|
19
|
+
type: 'data-source-fields',
|
|
20
|
+
defaultValue: () => [],
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
title: '方法定义',
|
|
26
|
+
items: [
|
|
27
|
+
{
|
|
28
|
+
name: 'methods',
|
|
29
|
+
type: 'data-source-methods',
|
|
30
|
+
defaultValue: () => [],
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
title: '事件配置',
|
|
36
|
+
items: [
|
|
37
|
+
{
|
|
38
|
+
name: 'events',
|
|
39
|
+
src: 'datasource',
|
|
40
|
+
type: 'event-select',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
title: 'mock数据',
|
|
46
|
+
items: [
|
|
47
|
+
{
|
|
48
|
+
name: 'mocks',
|
|
49
|
+
type: 'data-source-mocks',
|
|
50
|
+
defaultValue: () => [],
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
title: '请求参数裁剪',
|
|
56
|
+
display: (formState: FormState, { model }: any) => model.type === 'http',
|
|
57
|
+
items: [
|
|
58
|
+
{
|
|
59
|
+
name: 'beforeRequest',
|
|
60
|
+
type: 'vs-code',
|
|
61
|
+
parse: true,
|
|
62
|
+
height: '600px',
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
title: '响应数据裁剪',
|
|
68
|
+
display: (formState: FormState, { model }: any) => model.type === 'http',
|
|
69
|
+
items: [
|
|
70
|
+
{
|
|
71
|
+
name: 'afterResponse',
|
|
72
|
+
type: 'vs-code',
|
|
73
|
+
parse: true,
|
|
74
|
+
height: '600px',
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
export const getFormConfig = (type: string, configs: Record<string, FormConfig>): FormConfig => {
|
|
83
|
+
switch (type) {
|
|
84
|
+
case 'base':
|
|
85
|
+
return fillConfig([]);
|
|
86
|
+
case 'http':
|
|
87
|
+
return fillConfig(HttpFormConfig);
|
|
88
|
+
default:
|
|
89
|
+
return fillConfig(configs[type] || []);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const getFormValue = (type: string, values: Partial<DataSourceSchema>): Partial<DataSourceSchema> => {
|
|
94
|
+
if (type !== 'http') {
|
|
95
|
+
return values;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
beforeRequest: `(options, context) => {
|
|
100
|
+
/**
|
|
101
|
+
* 用户可以直接编写函数,在原始接口调用之前,会运行该函数,将这个函数的返回值作为该数据源接口的入参
|
|
102
|
+
*
|
|
103
|
+
* options: HttpOptions
|
|
104
|
+
*
|
|
105
|
+
* interface HttpOptions {
|
|
106
|
+
* // 请求链接
|
|
107
|
+
* url: string;
|
|
108
|
+
* // query参数
|
|
109
|
+
* params?: Record<string, string>;
|
|
110
|
+
* // body数据
|
|
111
|
+
* data?: Record<string, any>;
|
|
112
|
+
* // 请求头
|
|
113
|
+
* headers?: Record<string, string>;
|
|
114
|
+
* // 请求方法 GET/POST
|
|
115
|
+
* method?: Method;
|
|
116
|
+
* }
|
|
117
|
+
*
|
|
118
|
+
* context:上下文对象
|
|
119
|
+
*
|
|
120
|
+
* interface Content {
|
|
121
|
+
* app: AppCore;
|
|
122
|
+
* dataSource: HttpDataSource;
|
|
123
|
+
* }
|
|
124
|
+
*
|
|
125
|
+
* return: HttpOptions
|
|
126
|
+
*/
|
|
127
|
+
|
|
128
|
+
// 此处的返回值会作为这个接口的入参
|
|
129
|
+
return options;
|
|
130
|
+
}`,
|
|
131
|
+
afterResponse: `(response, context) => {
|
|
132
|
+
/**
|
|
133
|
+
* 用户可以直接编写函数,在原始接口返回之后,会运行该函数,将这个函数的返回值作为该数据源接口的返回
|
|
134
|
+
|
|
135
|
+
* context:上下文对象
|
|
136
|
+
*
|
|
137
|
+
* interface Content {
|
|
138
|
+
* app: AppCore;
|
|
139
|
+
* dataSource: HttpDataSource;
|
|
140
|
+
* }
|
|
141
|
+
*
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
// 此处的返回值会作为这个接口的返回值
|
|
145
|
+
return response;
|
|
146
|
+
}`,
|
|
147
|
+
...values,
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export const getDisplayField = (dataSources: DataSourceSchema[], key: string) => {
|
|
152
|
+
const displayState: { value: string; type: 'var' | 'text' }[] = [];
|
|
153
|
+
|
|
154
|
+
// 匹配es6字符串模块
|
|
155
|
+
const matches = key.matchAll(/\$\{([\s\S]+?)\}/g);
|
|
156
|
+
let index = 0;
|
|
157
|
+
for (const match of matches) {
|
|
158
|
+
if (typeof match.index === 'undefined') break;
|
|
159
|
+
|
|
160
|
+
// 字符串常量
|
|
161
|
+
displayState.push({
|
|
162
|
+
type: 'text',
|
|
163
|
+
value: key.substring(index, match.index),
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
let dsText = '';
|
|
167
|
+
let ds: DataSourceSchema | undefined;
|
|
168
|
+
let fields: DataSchema[] | undefined;
|
|
169
|
+
// 将模块解析成数据源对应的值
|
|
170
|
+
match[1]
|
|
171
|
+
.replaceAll(/\[(\d+)\]/g, '.$1')
|
|
172
|
+
.split('.')
|
|
173
|
+
.forEach((item, index) => {
|
|
174
|
+
if (index === 0) {
|
|
175
|
+
ds = dataSources.find((ds) => ds.id === item);
|
|
176
|
+
dsText += ds?.title || item;
|
|
177
|
+
fields = ds?.fields;
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (isNumber(item)) {
|
|
182
|
+
dsText += `[${item}]`;
|
|
183
|
+
} else {
|
|
184
|
+
const field = fields?.find((field) => field.name === item);
|
|
185
|
+
fields = field?.fields;
|
|
186
|
+
dsText += `.${field?.title || item}`;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
displayState.push({
|
|
191
|
+
type: 'var',
|
|
192
|
+
value: dsText,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
index = match.index + match[0].length;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (index < key.length) {
|
|
199
|
+
displayState.push({
|
|
200
|
+
type: 'text',
|
|
201
|
+
value: key.substring(index),
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return displayState;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
export const getCascaderOptionsFromFields = (
|
|
209
|
+
fields: DataSchema[] = [],
|
|
210
|
+
dataSourceFieldType: DataSourceFieldType[] = ['any'],
|
|
211
|
+
): CascaderOption[] => {
|
|
212
|
+
const child: CascaderOption[] = [];
|
|
213
|
+
fields.forEach((field) => {
|
|
214
|
+
if (!dataSourceFieldType.length) {
|
|
215
|
+
dataSourceFieldType.push('any');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
let children: CascaderOption[] = [];
|
|
219
|
+
if (field.type && ['any', 'array', 'object'].includes(field.type)) {
|
|
220
|
+
children = getCascaderOptionsFromFields(field.fields, dataSourceFieldType);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const item = {
|
|
224
|
+
label: `${field.title || field.name}(${field.type})`,
|
|
225
|
+
value: field.name,
|
|
226
|
+
children,
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const fieldType = field.type || 'any';
|
|
230
|
+
if (dataSourceFieldType.includes('any') || dataSourceFieldType.includes(fieldType)) {
|
|
231
|
+
child.push(item);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (!dataSourceFieldType.includes(fieldType) && !['array', 'object', 'any'].includes(fieldType)) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (!children.length && ['object', 'array', 'any'].includes(field.type || '')) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
child.push(item);
|
|
244
|
+
});
|
|
245
|
+
return child;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
export const removeDataSourceFieldPrefix = (id?: string) =>
|
|
249
|
+
id?.replace(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, '') || '';
|