diff --git a/packages/editor/src/fields/DataSourceFieldSelect/FieldSelect.vue b/packages/editor/src/fields/DataSourceFieldSelect/FieldSelect.vue
new file mode 100644
index 00000000..7f49ea34
--- /dev/null
+++ b/packages/editor/src/fields/DataSourceFieldSelect/FieldSelect.vue
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/editor/src/fields/DataSourceFieldSelect.vue b/packages/editor/src/fields/DataSourceFieldSelect/Index.vue
similarity index 50%
rename from packages/editor/src/fields/DataSourceFieldSelect.vue
rename to packages/editor/src/fields/DataSourceFieldSelect/Index.vue
index ac8236b8..6d2a2f2c 100644
--- a/packages/editor/src/fields/DataSourceFieldSelect.vue
+++ b/packages/editor/src/fields/DataSourceFieldSelect/Index.vue
@@ -1,8 +1,20 @@
+
+
-
-
import { computed, inject, ref, resolveComponent, watch } from 'vue';
-import { Coin, Edit, View } from '@element-plus/icons-vue';
+import { Coin } from '@element-plus/icons-vue';
-import { TMagicButton } from '@tmagic/design';
-import type { CascaderConfig, FieldProps, FormState } from '@tmagic/form';
-import { filterFunction, MCascader } from '@tmagic/form';
+import { TMagicButton, tMagicMessage } from '@tmagic/design';
+import type { FieldProps, FormState } from '@tmagic/form';
+import { DataSchema } from '@tmagic/schema';
import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX } from '@tmagic/utils';
import MIcon from '@editor/components/Icon.vue';
-import type { DataSourceFieldSelectConfig, EventBus, Services } from '@editor/type';
-import { SideItemKey } from '@editor/type';
-import { getCascaderOptionsFromFields } from '@editor/utils';
+import type { DataSourceFieldSelectConfig, Services } from '@editor/type';
+import { removeDataSourceFieldPrefix } from '@editor/utils';
+
+import FieldSelect from './FieldSelect.vue';
defineOptions({
name: 'MFieldsDataSourceFieldSelect',
});
-const services = inject('services');
-const eventBus = inject('eventBus');
const emit = defineEmits(['change']);
const props = withDefaults(defineProps>(), {
disabled: false,
});
-const notEditable = computed(() => filterFunction(mForm, props.config.notEditable, props));
-
-const hasDataSourceSidePanel = computed(() =>
- (services?.uiService.get('sideBarItems') || []).find((item) => item.$key === SideItemKey.DATA_SOURCE),
-);
-
-const selectedDataSourceId = computed(() => {
- const value = props.model[props.name];
- if (!Array.isArray(value) || !value.length) {
- return '';
- }
-
- return value[0].replace(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, '');
-});
-
-const dataSources = computed(() => services?.dataSourceService.get('dataSources'));
-
-const cascaderConfig = computed(() => {
- const valueIsKey = props.config.value === 'key';
-
- return {
- type: 'cascader',
- checkStrictly: props.config.checkStrictly ?? !valueIsKey,
- popperClass: 'm-editor-data-source-field-select-popper',
- options: () => {
- const options =
- dataSources.value?.map((ds) => ({
- label: ds.title || ds.id,
- value: valueIsKey ? ds.id : `${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}${ds.id}`,
- children: getCascaderOptionsFromFields(ds.fields, props.config.dataSourceFieldType),
- })) || [];
- return options.filter((option) => option.children.length);
- },
- };
-});
-
const showDataSourceFieldSelect = ref(false);
watch(
@@ -115,8 +82,11 @@ watch(
},
);
+const services = inject('services');
const mForm = inject('mForm');
+const dataSources = computed(() => services?.dataSourceService.get('dataSources') || []);
+
const type = computed((): string => {
let type = props.config.fieldConfig?.type;
if (typeof type === 'function') {
@@ -130,20 +100,60 @@ const type = computed((): string => {
});
const tagName = computed(() => {
- if (showDataSourceFieldSelect.value || !props.config.fieldConfig) {
- return MCascader;
- }
-
const component = resolveComponent(`m-${props.config.items ? 'form' : 'fields'}-${type.value}`);
if (typeof component !== 'string') return component;
return 'm-fields-text';
});
-const onChangeHandler = (value: any) => {
- emit('change', value);
-};
+const checkStrictly = computed(() => {
+ let value: boolean | undefined;
-const editHandler = (id: string) => {
- eventBus?.emit('edit-data-source', id);
+ if (typeof props.config.checkStrictly !== 'function') {
+ value = props.config.checkStrictly;
+ } else {
+ const dsId = removeDataSourceFieldPrefix(props.model[0]);
+ const dataSource = dataSources.value.find((ds) => ds.id === dsId);
+
+ value = props.config.checkStrictly(mForm, {
+ values: mForm?.initValues || {},
+ model: props.model,
+ parent: mForm?.parentValues || {},
+ formValue: mForm?.values || props.model,
+ prop: props.prop,
+ config: props.config,
+ dataSource,
+ });
+ }
+
+ return value ?? props.config.value === 'key';
+});
+
+const onChangeHandler = (value: string[]) => {
+ const [dsId, ...keys] = value;
+ const dataSource = dataSources.value.find((ds) => ds.id === removeDataSourceFieldPrefix(dsId));
+
+ let fields = dataSource?.fields || [];
+ let field: DataSchema | undefined;
+ (keys || []).forEach((key) => {
+ field = fields.find((f) => f.name === key);
+ fields = field?.fields || [];
+ });
+
+ const dataSourceFieldType = props.config.dataSourceFieldType || ['any'];
+ if (!dataSourceFieldType.length) {
+ dataSourceFieldType.push('any');
+ }
+
+ if (
+ !dsId ||
+ !keys.length ||
+ (field?.type &&
+ (field.type === 'any' || dataSourceFieldType.includes('any') || dataSourceFieldType.includes(field.type)))
+ ) {
+ emit('change', value);
+ } else {
+ tMagicMessage.error(`请选择类型为${dataSourceFieldType.join('或')}的字段`);
+ emit('change', [dsId]);
+ }
};
diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts
index b216a0e8..335534ee 100644
--- a/packages/editor/src/index.ts
+++ b/packages/editor/src/index.ts
@@ -22,7 +22,7 @@ import CodeLink from './fields/CodeLink.vue';
import CodeSelect from './fields/CodeSelect.vue';
import CodeSelectCol from './fields/CodeSelectCol.vue';
import DataSourceFields from './fields/DataSourceFields.vue';
-import DataSourceFieldSelect from './fields/DataSourceFieldSelect.vue';
+import DataSourceFieldSelect from './fields/DataSourceFieldSelect/Index.vue';
import DataSourceInput from './fields/DataSourceInput.vue';
import DataSourceMethods from './fields/DataSourceMethods.vue';
import DataSourceMethodSelect from './fields/DataSourceMethodSelect.vue';
@@ -68,7 +68,7 @@ export { default as DataSourceMethods } from './fields/DataSourceMethods.vue';
export { default as DataSourceInput } from './fields/DataSourceInput.vue';
export { default as DataSourceSelect } from './fields/DataSourceSelect.vue';
export { default as DataSourceMethodSelect } from './fields/DataSourceMethodSelect.vue';
-export { default as DataSourceFieldSelect } from './fields/DataSourceFieldSelect.vue';
+export { default as DataSourceFieldSelect } from './fields/DataSourceFieldSelect/Index.vue';
export { default as EventSelect } from './fields/EventSelect.vue';
export { default as KeyValue } from './fields/KeyValue.vue';
export { default as CodeBlockList } from './layouts/sidebar/code-block/CodeBlockList.vue';
diff --git a/packages/editor/src/theme/data-source-field-select.scss b/packages/editor/src/theme/data-source-field-select.scss
new file mode 100644
index 00000000..9992f65d
--- /dev/null
+++ b/packages/editor/src/theme/data-source-field-select.scss
@@ -0,0 +1,16 @@
+.m-fields-data-source-field-select {
+ width: 100%;
+ .m-editor-data-source-field-select {
+ display: flex;
+ width: 100%;
+
+ .tmagic-design-select {
+ flex: 1;
+ margin-right: 10px;
+ }
+
+ .tmagic-design-cascader {
+ flex: 2;
+ }
+ }
+}
diff --git a/packages/editor/src/theme/theme.scss b/packages/editor/src/theme/theme.scss
index cb87ec37..1c337472 100644
--- a/packages/editor/src/theme/theme.scss
+++ b/packages/editor/src/theme/theme.scss
@@ -25,3 +25,4 @@
@import "./floating-box.scss";
@import "./page-fragment-select.scss";
@import "./data-source-field.scss";
+@import "./data-source-field-select.scss";
diff --git a/packages/editor/src/type.ts b/packages/editor/src/type.ts
index e4bcfcfe..af33dcbe 100644
--- a/packages/editor/src/type.ts
+++ b/packages/editor/src/type.ts
@@ -20,11 +20,12 @@ import type { Component } from 'vue';
import type EventEmitter from 'events';
import type { PascalCasedProperties } from 'type-fest';
-import type { ChildConfig, ColumnConfig, FilterFunction, FormConfig, FormItem, Input } from '@tmagic/form';
+import type { ChildConfig, ColumnConfig, FilterFunction, FormConfig, FormItem, FormState, Input } from '@tmagic/form';
import type {
CodeBlockContent,
CodeBlockDSL,
DataSourceFieldType,
+ DataSourceSchema,
Id,
MApp,
MContainer,
@@ -646,13 +647,27 @@ export interface DataSourceMethodSelectConfig extends FormItem {
export interface DataSourceFieldSelectConfig extends FormItem {
type: 'data-source-field-select';
- /** 是否要编译成数据源的data。
+ /**
+ * 是否要编译成数据源的data。
* key: 不编译,就是要数据源id和field name;
* value: 要编译(数据源data[`${filed}`])
* */
value?: 'key' | 'value';
/** 是否严格的遵守父子节点不互相关联 */
- checkStrictly?: boolean;
+ checkStrictly?:
+ | boolean
+ | ((
+ mForm: FormState | undefined,
+ data: {
+ model: Record;
+ values: Record;
+ parent?: Record;
+ formValue: Record;
+ prop: string;
+ config: DataSourceFieldSelectConfig;
+ dataSource?: DataSourceSchema;
+ },
+ ) => boolean);
dataSourceFieldType?: DataSourceFieldType[];
fieldConfig?: ChildConfig;
/** 是否可以编辑数据源,disable表示的是是否可以选择数据源 */
diff --git a/packages/editor/src/utils/data-source/index.ts b/packages/editor/src/utils/data-source/index.ts
index 409e5cd7..9df6f372 100644
--- a/packages/editor/src/utils/data-source/index.ts
+++ b/packages/editor/src/utils/data-source/index.ts
@@ -1,6 +1,6 @@
import { CascaderOption, FormConfig, FormState } from '@tmagic/form';
import { DataSchema, DataSourceFieldType, DataSourceSchema } from '@tmagic/schema';
-import { isNumber } from '@tmagic/utils';
+import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, isNumber } from '@tmagic/utils';
import BaseFormConfig from './formConfigs/base';
import HttpFormConfig from './formConfigs/http';
@@ -218,7 +218,7 @@ export const getCascaderOptionsFromFields = (
const children = getCascaderOptionsFromFields(field.fields, dataSourceFieldType);
const item = {
- label: field.title || field.name,
+ label: `${field.title || field.name}(${field.type})`,
value: field.name,
children,
};
@@ -241,3 +241,6 @@ export const getCascaderOptionsFromFields = (
});
return child;
};
+
+export const removeDataSourceFieldPrefix = (id?: string) =>
+ id?.replace(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, '') || '';
diff --git a/packages/ui-react/src/iterator-container/src/formConfig.ts b/packages/ui-react/src/iterator-container/src/formConfig.ts
index aef707b4..212a97c5 100644
--- a/packages/ui-react/src/iterator-container/src/formConfig.ts
+++ b/packages/ui-react/src/iterator-container/src/formConfig.ts
@@ -23,17 +23,15 @@ export default [
text: '数据源数据',
value: 'value',
dataSourceFieldType: ['array'],
- checkStrictly: false,
+ checkStrictly: true,
type: 'data-source-field-select',
onChange: (vm: any, v: string[] = [], { model }: any) => {
- if (Array.isArray(v)) {
+ if (Array.isArray(v) && v.length > 1) {
const [dsId, ...keys] = v;
model.dsField = [dsId.replace(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, ''), ...keys];
} else {
model.dsField = [];
}
-
- return v;
},
},
{
diff --git a/packages/ui-vue2/src/iterator-container/src/formConfig.ts b/packages/ui-vue2/src/iterator-container/src/formConfig.ts
index 84abf3cf..212a97c5 100644
--- a/packages/ui-vue2/src/iterator-container/src/formConfig.ts
+++ b/packages/ui-vue2/src/iterator-container/src/formConfig.ts
@@ -23,10 +23,10 @@ export default [
text: '数据源数据',
value: 'value',
dataSourceFieldType: ['array'],
- checkStrictly: false,
+ checkStrictly: true,
type: 'data-source-field-select',
onChange: (vm: any, v: string[] = [], { model }: any) => {
- if (Array.isArray(v)) {
+ if (Array.isArray(v) && v.length > 1) {
const [dsId, ...keys] = v;
model.dsField = [dsId.replace(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, ''), ...keys];
} else {
diff --git a/packages/ui/src/iterator-container/src/formConfig.ts b/packages/ui/src/iterator-container/src/formConfig.ts
index 84abf3cf..212a97c5 100644
--- a/packages/ui/src/iterator-container/src/formConfig.ts
+++ b/packages/ui/src/iterator-container/src/formConfig.ts
@@ -23,10 +23,10 @@ export default [
text: '数据源数据',
value: 'value',
dataSourceFieldType: ['array'],
- checkStrictly: false,
+ checkStrictly: true,
type: 'data-source-field-select',
onChange: (vm: any, v: string[] = [], { model }: any) => {
- if (Array.isArray(v)) {
+ if (Array.isArray(v) && v.length > 1) {
const [dsId, ...keys] = v;
model.dsField = [dsId.replace(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, ''), ...keys];
} else {