@tmagic/editor 1.4.9 → 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 +12 -10
- package/src/Editor.vue +2 -1
- package/src/editorProps.ts +3 -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 +6 -0
- package/src/fields/DisplayConds.vue +145 -0
- package/src/index.ts +8 -2
- package/src/layouts/Framework.vue +4 -2
- package/src/layouts/page-bar/PageBar.vue +8 -2
- package/src/layouts/page-bar/PageBarScrollContainer.vue +40 -4
- package/src/layouts/page-bar/PageList.vue +55 -0
- package/src/services/ui.ts +1 -0
- package/src/theme/data-source-field-select.scss +16 -0
- package/src/theme/page-bar.scss +13 -0
- package/src/theme/theme.scss +1 -0
- package/src/type.ts +35 -4
- package/src/utils/data-source/index.ts +9 -3
- package/src/utils/props.ts +6 -103
- 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
- package/src/fields/DataSourceFieldSelect.vue +0 -149
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.4.
|
|
2
|
+
"version": "1.4.10",
|
|
3
3
|
"name": "@tmagic/editor",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -54,14 +54,16 @@
|
|
|
54
54
|
"lodash-es": "^4.17.21",
|
|
55
55
|
"moveable": "^0.53.0",
|
|
56
56
|
"serialize-javascript": "^6.0.0",
|
|
57
|
-
"
|
|
58
|
-
"@tmagic/
|
|
57
|
+
"sortablejs": "^1.15.2",
|
|
58
|
+
"@tmagic/dep": "1.4.10",
|
|
59
|
+
"@tmagic/table": "1.4.10"
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
62
|
"@types/events": "^3.0.0",
|
|
62
63
|
"@types/lodash-es": "^4.17.4",
|
|
63
64
|
"@types/node": "^18.19.0",
|
|
64
65
|
"@types/serialize-javascript": "^5.0.1",
|
|
66
|
+
"@types/sortablejs": "^1.15.8",
|
|
65
67
|
"@vitejs/plugin-vue": "^5.0.4",
|
|
66
68
|
"@vue/compiler-sfc": "^3.4.27",
|
|
67
69
|
"@vue/test-utils": "^2.4.6",
|
|
@@ -74,14 +76,14 @@
|
|
|
74
76
|
},
|
|
75
77
|
"peerDependencies": {
|
|
76
78
|
"monaco-editor": "^0.48.0",
|
|
77
|
-
"vue": "^3.4.27",
|
|
78
79
|
"typescript": "*",
|
|
79
|
-
"
|
|
80
|
-
"@tmagic/
|
|
81
|
-
"@tmagic/design": "1.4.
|
|
82
|
-
"@tmagic/schema": "1.4.
|
|
83
|
-
"@tmagic/
|
|
84
|
-
"@tmagic/stage": "1.4.
|
|
80
|
+
"vue": "^3.4.27",
|
|
81
|
+
"@tmagic/core": "1.4.10",
|
|
82
|
+
"@tmagic/design": "1.4.10",
|
|
83
|
+
"@tmagic/schema": "1.4.10",
|
|
84
|
+
"@tmagic/form": "1.4.10",
|
|
85
|
+
"@tmagic/stage": "1.4.10",
|
|
86
|
+
"@tmagic/utils": "1.4.10"
|
|
85
87
|
},
|
|
86
88
|
"peerDependenciesMeta": {
|
|
87
89
|
"typescript": {
|
package/src/Editor.vue
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<Framework :disabled-page-fragment="disabledPageFragment">
|
|
2
|
+
<Framework :disabled-page-fragment="disabledPageFragment" :page-bar-sort-options="pageBarSortOptions">
|
|
3
3
|
<template #header>
|
|
4
4
|
<slot name="header"></slot>
|
|
5
5
|
</template>
|
|
@@ -106,6 +106,7 @@
|
|
|
106
106
|
<template #page-bar><slot name="page-bar"></slot></template>
|
|
107
107
|
<template #page-bar-title="{ page }"><slot name="page-bar-title" :page="page"></slot></template>
|
|
108
108
|
<template #page-bar-popover="{ page }"><slot name="page-bar-popover" :page="page"></slot></template>
|
|
109
|
+
<template #page-list-popover="{ list }"><slot name="page-list-popover" :list="list"></slot></template>
|
|
109
110
|
</Framework>
|
|
110
111
|
</template>
|
|
111
112
|
|
package/src/editorProps.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
MenuBarData,
|
|
18
18
|
MenuButton,
|
|
19
19
|
MenuComponent,
|
|
20
|
+
PageBarSortOptions,
|
|
20
21
|
SideBarData,
|
|
21
22
|
StageRect,
|
|
22
23
|
} from './type';
|
|
@@ -90,6 +91,8 @@ export interface EditorProps {
|
|
|
90
91
|
/** 用于自定义组件树与画布的右键菜单 */
|
|
91
92
|
customContentMenu?: (menus: (MenuButton | MenuComponent)[], type: string) => (MenuButton | MenuComponent)[];
|
|
92
93
|
extendFormState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
|
|
94
|
+
/** 页面顺序拖拽配置参数 */
|
|
95
|
+
pageBarSortOptions?: PageBarSortOptions;
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
export const defaultEditorProps = {
|
|
@@ -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>
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="m-fields-data-source-field-select">
|
|
3
|
+
<FieldSelect
|
|
4
|
+
v-if="showDataSourceFieldSelect || !config.fieldConfig"
|
|
5
|
+
:model-value="model[name]"
|
|
6
|
+
:disabled="disabled"
|
|
7
|
+
:size="size"
|
|
8
|
+
:value="config.value"
|
|
9
|
+
:checkStrictly="checkStrictly"
|
|
10
|
+
:dataSourceFieldType="config.dataSourceFieldType"
|
|
11
|
+
@change="onChangeHandler"
|
|
12
|
+
></FieldSelect>
|
|
13
|
+
|
|
14
|
+
<component
|
|
15
|
+
v-else
|
|
16
|
+
:is="tagName"
|
|
17
|
+
:config="config.fieldConfig"
|
|
18
|
+
:model="model"
|
|
19
|
+
:name="name"
|
|
20
|
+
:disabled="disabled"
|
|
21
|
+
:size="size"
|
|
22
|
+
:last-values="lastValues"
|
|
23
|
+
:init-values="initValues"
|
|
24
|
+
:values="values"
|
|
25
|
+
:prop="`${prop}${prop ? '.' : ''}${name}`"
|
|
26
|
+
@change="onChangeHandler"
|
|
27
|
+
></component>
|
|
28
|
+
|
|
29
|
+
<TMagicButton
|
|
30
|
+
v-if="config.fieldConfig"
|
|
31
|
+
style="margin-left: 5px"
|
|
32
|
+
:type="showDataSourceFieldSelect ? 'primary' : 'default'"
|
|
33
|
+
:size="size"
|
|
34
|
+
@click="showDataSourceFieldSelect = !showDataSourceFieldSelect"
|
|
35
|
+
><MIcon :icon="Coin"></MIcon
|
|
36
|
+
></TMagicButton>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
39
|
+
|
|
40
|
+
<script setup lang="ts">
|
|
41
|
+
import { computed, inject, ref, resolveComponent, watch } from 'vue';
|
|
42
|
+
import { Coin } from '@element-plus/icons-vue';
|
|
43
|
+
|
|
44
|
+
import { TMagicButton, tMagicMessage } from '@tmagic/design';
|
|
45
|
+
import type { FieldProps, FormState } from '@tmagic/form';
|
|
46
|
+
import { DataSchema } from '@tmagic/schema';
|
|
47
|
+
import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX } from '@tmagic/utils';
|
|
48
|
+
|
|
49
|
+
import MIcon from '@editor/components/Icon.vue';
|
|
50
|
+
import type { DataSourceFieldSelectConfig, Services } from '@editor/type';
|
|
51
|
+
import { removeDataSourceFieldPrefix } from '@editor/utils';
|
|
52
|
+
|
|
53
|
+
import FieldSelect from './FieldSelect.vue';
|
|
54
|
+
|
|
55
|
+
defineOptions({
|
|
56
|
+
name: 'MFieldsDataSourceFieldSelect',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const emit = defineEmits(['change']);
|
|
60
|
+
|
|
61
|
+
const props = withDefaults(defineProps<FieldProps<DataSourceFieldSelectConfig>>(), {
|
|
62
|
+
disabled: false,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const showDataSourceFieldSelect = ref(false);
|
|
66
|
+
|
|
67
|
+
watch(
|
|
68
|
+
() => props.model[props.name],
|
|
69
|
+
(value) => {
|
|
70
|
+
if (
|
|
71
|
+
Array.isArray(value) &&
|
|
72
|
+
typeof value[0] === 'string' &&
|
|
73
|
+
value[0].startsWith(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX)
|
|
74
|
+
) {
|
|
75
|
+
showDataSourceFieldSelect.value = true;
|
|
76
|
+
} else {
|
|
77
|
+
showDataSourceFieldSelect.value = false;
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
immediate: true,
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
const services = inject<Services>('services');
|
|
86
|
+
const mForm = inject<FormState | undefined>('mForm');
|
|
87
|
+
|
|
88
|
+
const dataSources = computed(() => services?.dataSourceService.get('dataSources') || []);
|
|
89
|
+
|
|
90
|
+
const type = computed((): string => {
|
|
91
|
+
let type = props.config.fieldConfig?.type;
|
|
92
|
+
if (typeof type === 'function') {
|
|
93
|
+
type = type(mForm, {
|
|
94
|
+
model: props.model,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (type === 'form') return '';
|
|
98
|
+
if (type === 'container') return '';
|
|
99
|
+
return type?.replace(/([A-Z])/g, '-$1').toLowerCase() || (props.config.items ? '' : 'text');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const tagName = computed(() => {
|
|
103
|
+
const component = resolveComponent(`m-${props.config.items ? 'form' : 'fields'}-${type.value}`);
|
|
104
|
+
if (typeof component !== 'string') return component;
|
|
105
|
+
return 'm-fields-text';
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const checkStrictly = computed(() => {
|
|
109
|
+
let value: boolean | undefined;
|
|
110
|
+
|
|
111
|
+
if (typeof props.config.checkStrictly !== 'function') {
|
|
112
|
+
value = props.config.checkStrictly;
|
|
113
|
+
} else {
|
|
114
|
+
const dsId = removeDataSourceFieldPrefix(props.model[0]);
|
|
115
|
+
const dataSource = dataSources.value.find((ds) => ds.id === dsId);
|
|
116
|
+
|
|
117
|
+
value = props.config.checkStrictly(mForm, {
|
|
118
|
+
values: mForm?.initValues || {},
|
|
119
|
+
model: props.model,
|
|
120
|
+
parent: mForm?.parentValues || {},
|
|
121
|
+
formValue: mForm?.values || props.model,
|
|
122
|
+
prop: props.prop,
|
|
123
|
+
config: props.config,
|
|
124
|
+
dataSource,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return value ?? props.config.value === 'key';
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const onChangeHandler = (value: string[]) => {
|
|
132
|
+
if (!Array.isArray(value)) {
|
|
133
|
+
emit('change', value);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const [dsId, ...keys] = value;
|
|
138
|
+
const dataSource = dataSources.value.find((ds) => ds.id === removeDataSourceFieldPrefix(dsId));
|
|
139
|
+
|
|
140
|
+
if (!dataSource) {
|
|
141
|
+
emit('change', value);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let fields = dataSource.fields || [];
|
|
146
|
+
let field: DataSchema | undefined;
|
|
147
|
+
(keys || []).forEach((key) => {
|
|
148
|
+
field = fields.find((f) => f.name === key);
|
|
149
|
+
fields = field?.fields || [];
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const dataSourceFieldType = props.config.dataSourceFieldType || ['any'];
|
|
153
|
+
if (!dataSourceFieldType.length) {
|
|
154
|
+
dataSourceFieldType.push('any');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (
|
|
158
|
+
!keys.length ||
|
|
159
|
+
(field?.type &&
|
|
160
|
+
(field.type === 'any' || dataSourceFieldType.includes('any') || dataSourceFieldType.includes(field.type)))
|
|
161
|
+
) {
|
|
162
|
+
emit('change', value);
|
|
163
|
+
} else {
|
|
164
|
+
tMagicMessage.error(`请选择类型为${dataSourceFieldType.join('或')}的字段`);
|
|
165
|
+
emit('change', [dsId]);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
</script>
|
|
@@ -172,6 +172,12 @@ const dataSourceFieldsConfig: FormConfig = [
|
|
|
172
172
|
{ text: 'null', value: 'null' },
|
|
173
173
|
{ text: 'any', value: 'any' },
|
|
174
174
|
],
|
|
175
|
+
onChange: (formState, v: string, { model }) => {
|
|
176
|
+
if (!['any', 'array', 'object'].includes(v)) {
|
|
177
|
+
model.fields = [];
|
|
178
|
+
}
|
|
179
|
+
return v;
|
|
180
|
+
},
|
|
175
181
|
},
|
|
176
182
|
{
|
|
177
183
|
name: 'name',
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<MGroupList
|
|
3
|
+
style="width: 100%"
|
|
4
|
+
:config="config"
|
|
5
|
+
:name="name"
|
|
6
|
+
:disabled="disabled"
|
|
7
|
+
:model="model"
|
|
8
|
+
:last-values="lastValues"
|
|
9
|
+
:prop="prop"
|
|
10
|
+
:size="size"
|
|
11
|
+
></MGroupList>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script lang="ts" setup>
|
|
15
|
+
import { computed, inject } from 'vue';
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
type FieldProps,
|
|
19
|
+
type FilterFunction,
|
|
20
|
+
filterFunction,
|
|
21
|
+
type FormState,
|
|
22
|
+
type GroupListConfig,
|
|
23
|
+
MGroupList,
|
|
24
|
+
} from '@tmagic/form';
|
|
25
|
+
|
|
26
|
+
import type { Services } from '@editor/type';
|
|
27
|
+
import { getCascaderOptionsFromFields } from '@editor/utils';
|
|
28
|
+
|
|
29
|
+
defineOptions({
|
|
30
|
+
name: 'm-fields-display-conds',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const props = withDefaults(
|
|
34
|
+
defineProps<
|
|
35
|
+
FieldProps<{
|
|
36
|
+
titlePrefix?: string;
|
|
37
|
+
parentFields?: string[] | FilterFunction<string[]>;
|
|
38
|
+
}>
|
|
39
|
+
>(),
|
|
40
|
+
{
|
|
41
|
+
disabled: false,
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const { dataSourceService } = inject<Services>('services') || {};
|
|
46
|
+
const mForm = inject<FormState | undefined>('mForm');
|
|
47
|
+
|
|
48
|
+
const parentFields = computed(() => filterFunction<string[]>(mForm, props.config.parentFields, props) || []);
|
|
49
|
+
|
|
50
|
+
const config = computed<GroupListConfig>(() => ({
|
|
51
|
+
type: 'groupList',
|
|
52
|
+
name: props.name,
|
|
53
|
+
titlePrefix: props.config.titlePrefix,
|
|
54
|
+
expandAll: true,
|
|
55
|
+
items: [
|
|
56
|
+
{
|
|
57
|
+
type: 'table',
|
|
58
|
+
name: 'cond',
|
|
59
|
+
operateColWidth: 50,
|
|
60
|
+
items: [
|
|
61
|
+
parentFields.value.length
|
|
62
|
+
? {
|
|
63
|
+
type: 'cascader',
|
|
64
|
+
options: () => {
|
|
65
|
+
const [dsId, ...keys] = parentFields.value;
|
|
66
|
+
const ds = dataSourceService?.getDataSourceById(dsId);
|
|
67
|
+
if (!ds) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let fields = ds.fields || [];
|
|
72
|
+
keys.forEach((key) => {
|
|
73
|
+
const field = fields.find((f) => f.name === key);
|
|
74
|
+
fields = field?.fields || [];
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
return getCascaderOptionsFromFields(fields, ['string', 'number', 'boolean', 'any']);
|
|
78
|
+
},
|
|
79
|
+
name: 'field',
|
|
80
|
+
value: 'key',
|
|
81
|
+
label: '字段',
|
|
82
|
+
checkStrictly: false,
|
|
83
|
+
}
|
|
84
|
+
: {
|
|
85
|
+
type: 'data-source-field-select',
|
|
86
|
+
name: 'field',
|
|
87
|
+
value: 'key',
|
|
88
|
+
label: '字段',
|
|
89
|
+
checkStrictly: false,
|
|
90
|
+
dataSourceFieldType: ['string', 'number', 'boolean', 'any'],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
type: 'cond-op-select',
|
|
94
|
+
parentFields: parentFields.value,
|
|
95
|
+
label: '条件',
|
|
96
|
+
width: 100,
|
|
97
|
+
name: 'op',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
label: '值',
|
|
101
|
+
width: 100,
|
|
102
|
+
items: [
|
|
103
|
+
{
|
|
104
|
+
name: 'value',
|
|
105
|
+
type: (mForm, { model }) => {
|
|
106
|
+
const [id, ...fieldNames] = model.field;
|
|
107
|
+
|
|
108
|
+
const ds = dataSourceService?.getDataSourceById(id);
|
|
109
|
+
|
|
110
|
+
let fields = ds?.fields || [];
|
|
111
|
+
let type = '';
|
|
112
|
+
(fieldNames || []).forEach((fieldName: string) => {
|
|
113
|
+
const field = fields.find((f) => f.name === fieldName);
|
|
114
|
+
fields = field?.fields || [];
|
|
115
|
+
type = field?.type || '';
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
if (type === 'number') {
|
|
119
|
+
return 'number';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (type === 'boolean') {
|
|
123
|
+
return 'select';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return 'text';
|
|
127
|
+
},
|
|
128
|
+
options: [
|
|
129
|
+
{ text: 'true', value: true },
|
|
130
|
+
{ text: 'false', value: false },
|
|
131
|
+
],
|
|
132
|
+
display: (vm, { model }) => !['between', 'not_between'].includes(model.op),
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: 'range',
|
|
136
|
+
type: 'number-range',
|
|
137
|
+
display: (vm, { model }) => ['between', 'not_between'].includes(model.op),
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
}));
|
|
145
|
+
</script>
|
package/src/index.ts
CHANGED
|
@@ -21,13 +21,15 @@ import Code from './fields/Code.vue';
|
|
|
21
21
|
import CodeLink from './fields/CodeLink.vue';
|
|
22
22
|
import CodeSelect from './fields/CodeSelect.vue';
|
|
23
23
|
import CodeSelectCol from './fields/CodeSelectCol.vue';
|
|
24
|
+
import CondOpSelect from './fields/CondOpSelect.vue';
|
|
24
25
|
import DataSourceFields from './fields/DataSourceFields.vue';
|
|
25
|
-
import DataSourceFieldSelect from './fields/DataSourceFieldSelect.vue';
|
|
26
|
+
import DataSourceFieldSelect from './fields/DataSourceFieldSelect/Index.vue';
|
|
26
27
|
import DataSourceInput from './fields/DataSourceInput.vue';
|
|
27
28
|
import DataSourceMethods from './fields/DataSourceMethods.vue';
|
|
28
29
|
import DataSourceMethodSelect from './fields/DataSourceMethodSelect.vue';
|
|
29
30
|
import DataSourceMocks from './fields/DataSourceMocks.vue';
|
|
30
31
|
import DataSourceSelect from './fields/DataSourceSelect.vue';
|
|
32
|
+
import DisplayConds from './fields/DisplayConds.vue';
|
|
31
33
|
import EventSelect from './fields/EventSelect.vue';
|
|
32
34
|
import KeyValue from './fields/KeyValue.vue';
|
|
33
35
|
import PageFragmentSelect from './fields/PageFragmentSelect.vue';
|
|
@@ -68,7 +70,7 @@ export { default as DataSourceMethods } from './fields/DataSourceMethods.vue';
|
|
|
68
70
|
export { default as DataSourceInput } from './fields/DataSourceInput.vue';
|
|
69
71
|
export { default as DataSourceSelect } from './fields/DataSourceSelect.vue';
|
|
70
72
|
export { default as DataSourceMethodSelect } from './fields/DataSourceMethodSelect.vue';
|
|
71
|
-
export { default as DataSourceFieldSelect } from './fields/DataSourceFieldSelect.vue';
|
|
73
|
+
export { default as DataSourceFieldSelect } from './fields/DataSourceFieldSelect/Index.vue';
|
|
72
74
|
export { default as EventSelect } from './fields/EventSelect.vue';
|
|
73
75
|
export { default as KeyValue } from './fields/KeyValue.vue';
|
|
74
76
|
export { default as CodeBlockList } from './layouts/sidebar/code-block/CodeBlockList.vue';
|
|
@@ -84,6 +86,8 @@ export { default as Resizer } from './components/Resizer.vue';
|
|
|
84
86
|
export { default as CodeBlockEditor } from './components/CodeBlockEditor.vue';
|
|
85
87
|
export { default as FloatingBox } from './components/FloatingBox.vue';
|
|
86
88
|
export { default as PageFragmentSelect } from './fields/PageFragmentSelect.vue';
|
|
89
|
+
export { default as DisplayConds } from './fields/DisplayConds.vue';
|
|
90
|
+
export { default as CondOpSelect } from './fields/CondOpSelect.vue';
|
|
87
91
|
|
|
88
92
|
const defaultInstallOpt: InstallOptions = {
|
|
89
93
|
// eslint-disable-next-line no-eval
|
|
@@ -114,5 +118,7 @@ export default {
|
|
|
114
118
|
app.component('m-fields-data-source-method-select', DataSourceMethodSelect);
|
|
115
119
|
app.component('m-fields-data-source-field-select', DataSourceFieldSelect);
|
|
116
120
|
app.component('m-fields-page-fragment-select', PageFragmentSelect);
|
|
121
|
+
app.component('m-fields-display-conds', DisplayConds);
|
|
122
|
+
app.component('m-fields-cond-op-select', CondOpSelect);
|
|
117
123
|
},
|
|
118
124
|
};
|