mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-09-14 07:59:46 +00:00
fix(editor): 统一数据源字段路径解析并优化 typeMatch 校验
修复 ds-field:: 前缀解析、checkStrictly 数据源取值及字段类型不匹配时的校验提示。
This commit is contained in:
parent
050814f3f8
commit
05fbdb17b5
@ -31,6 +31,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { getDesignConfig, TMagicSelect } from '@tmagic/design';
|
import { getDesignConfig, TMagicSelect } from '@tmagic/design';
|
||||||
import type { CondOpSelectConfig, FieldProps } from '@tmagic/form';
|
import type { CondOpSelectConfig, FieldProps } from '@tmagic/form';
|
||||||
|
import { removeDataSourceFieldPrefix } from '@tmagic/utils';
|
||||||
|
|
||||||
import { useServices } from '@editor/hooks/use-services';
|
import { useServices } from '@editor/hooks/use-services';
|
||||||
import { getCondOpOptionsByFieldType, getFieldType } from '@editor/utils';
|
import { getCondOpOptionsByFieldType, getFieldType } from '@editor/utils';
|
||||||
@ -50,8 +51,8 @@ const props = defineProps<FieldProps<CondOpSelectConfig>>();
|
|||||||
const optionComponent = getDesignConfig('components')?.option;
|
const optionComponent = getDesignConfig('components')?.option;
|
||||||
|
|
||||||
const options = computed(() => {
|
const options = computed(() => {
|
||||||
const [id, ...fieldNames] = [...(props.config.parentFields || []), ...props.model.field];
|
const [id, ...fieldNames] = [...(props.config.parentFields || []), ...(props.model.field || [])];
|
||||||
const ds = dataSourceService.getDataSourceById(id);
|
const ds = id ? dataSourceService.getDataSourceById(removeDataSourceFieldPrefix(id)) : undefined;
|
||||||
const type = getFieldType(ds, fieldNames);
|
const type = getFieldType(ds, fieldNames);
|
||||||
return getCondOpOptionsByFieldType(type);
|
return getCondOpOptionsByFieldType(type);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -143,7 +143,10 @@ const checkStrictly = computed(() => {
|
|||||||
if (typeof props.config.checkStrictly !== 'function') {
|
if (typeof props.config.checkStrictly !== 'function') {
|
||||||
value = props.config.checkStrictly;
|
value = props.config.checkStrictly;
|
||||||
} else {
|
} else {
|
||||||
const dsId = removeDataSourceFieldPrefix(props.model[0]);
|
const fieldValue = props.model[props.name];
|
||||||
|
// 指定了 dataSourceId 时取值里只有字段名,数据源 id 只能取自 config
|
||||||
|
const rawDsId = props.config.dataSourceId ?? (Array.isArray(fieldValue) ? fieldValue[0] : fieldValue);
|
||||||
|
const dsId = removeDataSourceFieldPrefix(`${rawDsId}`);
|
||||||
const dataSource = dataSources.value.find((ds) => ds.id === dsId);
|
const dataSource = dataSources.value.find((ds) => ds.id === dsId);
|
||||||
|
|
||||||
value = props.config.checkStrictly(mForm, {
|
value = props.config.checkStrictly(mForm, {
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import {
|
|||||||
type GroupListConfig,
|
type GroupListConfig,
|
||||||
MGroupList,
|
MGroupList,
|
||||||
} from '@tmagic/form';
|
} from '@tmagic/form';
|
||||||
|
import { removeDataSourceFieldPrefix } from '@tmagic/utils';
|
||||||
|
|
||||||
import { useServices } from '@editor/hooks/use-services';
|
import { useServices } from '@editor/hooks/use-services';
|
||||||
import { getCascaderOptionsFromFields, getFieldType } from '@editor/utils';
|
import { getCascaderOptionsFromFields, getFieldType } from '@editor/utils';
|
||||||
@ -46,9 +47,14 @@ const mForm = inject<FormState | undefined>('mForm');
|
|||||||
|
|
||||||
const parentFields = computed(() => filterFunction<string[]>(mForm, props.config.parentFields, props) || []);
|
const parentFields = computed(() => filterFunction<string[]>(mForm, props.config.parentFields, props) || []);
|
||||||
|
|
||||||
|
const resolveFieldPath = (path: string[]) => {
|
||||||
|
const [id, ...fieldNames] = path;
|
||||||
|
const ds = id ? dataSourceService.getDataSourceById(removeDataSourceFieldPrefix(`${id}`)) : undefined;
|
||||||
|
return { ds, fieldNames };
|
||||||
|
};
|
||||||
|
|
||||||
const fieldOnChange = (_formState: FormState | undefined, v: string[], { model }: { model: Record<string, any> }) => {
|
const fieldOnChange = (_formState: FormState | undefined, v: string[], { model }: { model: Record<string, any> }) => {
|
||||||
const [id, ...fieldNames] = [...parentFields.value, ...v];
|
const { ds, fieldNames } = resolveFieldPath([...parentFields.value, ...v]);
|
||||||
const ds = dataSourceService.getDataSourceById(id);
|
|
||||||
const type = getFieldType(ds, fieldNames);
|
const type = getFieldType(ds, fieldNames);
|
||||||
if (type === 'number') {
|
if (type === 'number') {
|
||||||
model.value = Number(model.value);
|
model.value = Number(model.value);
|
||||||
@ -82,14 +88,13 @@ const config = computed<GroupListConfig>(() => ({
|
|||||||
? {
|
? {
|
||||||
type: 'cascader',
|
type: 'cascader',
|
||||||
options: () => {
|
options: () => {
|
||||||
const [dsId, ...keys] = parentFields.value;
|
const { ds, fieldNames } = resolveFieldPath(parentFields.value);
|
||||||
const ds = dataSourceService.getDataSourceById(dsId);
|
|
||||||
if (!ds) {
|
if (!ds) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
let fields = ds.fields || [];
|
let fields = ds.fields || [];
|
||||||
keys.forEach((key) => {
|
fieldNames.forEach((key) => {
|
||||||
const field = fields.find((f) => f.name === key);
|
const field = fields.find((f) => f.name === key);
|
||||||
fields = field?.fields || [];
|
fields = field?.fields || [];
|
||||||
});
|
});
|
||||||
@ -139,8 +144,7 @@ const config = computed<GroupListConfig>(() => ({
|
|||||||
{
|
{
|
||||||
name: 'value',
|
name: 'value',
|
||||||
type: (_mForm, { model }) => {
|
type: (_mForm, { model }) => {
|
||||||
const [id, ...fieldNames] = [...parentFields.value, ...model.field];
|
const { ds, fieldNames } = resolveFieldPath([...parentFields.value, ...(model.field || [])]);
|
||||||
const ds = dataSourceService.getDataSourceById(id);
|
|
||||||
const type = getFieldType(ds, fieldNames);
|
const type = getFieldType(ds, fieldNames);
|
||||||
|
|
||||||
if (type === 'number') {
|
if (type === 'number') {
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import { appendValidateSuggestion } from '@tmagic/design';
|
|||||||
import { type ContainerChangeEventData, defineFormConfig, MContainer } from '@tmagic/form';
|
import { type ContainerChangeEventData, defineFormConfig, MContainer } from '@tmagic/form';
|
||||||
import type { StyleSchema } from '@tmagic/schema';
|
import type { StyleSchema } from '@tmagic/schema';
|
||||||
|
|
||||||
import { validateDataSourceFieldSelectValue } from '@editor/utils/type-match-rules';
|
import { validateDataSourceFieldSelect } from '@editor/utils/type-match-rules';
|
||||||
|
|
||||||
import { AlignCenter, AlignLeft, AlignRight } from '../icons/text-align';
|
import { AlignCenter, AlignLeft, AlignRight } from '../icons/text-align';
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ const formConfig = defineFormConfig([
|
|||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = validateDataSourceFieldSelectValue(
|
const result = validateDataSourceFieldSelect(
|
||||||
value,
|
value,
|
||||||
{
|
{
|
||||||
fieldType: 'data-source-field-select',
|
fieldType: 'data-source-field-select',
|
||||||
|
|||||||
@ -209,7 +209,6 @@ const validateDataSourceFieldPath = (
|
|||||||
path: string[],
|
path: string[],
|
||||||
options: {
|
options: {
|
||||||
dataSourceId?: string;
|
dataSourceId?: string;
|
||||||
valueMode?: 'key' | 'value';
|
|
||||||
dataSourceFieldType?: DataSourceFieldType[];
|
dataSourceFieldType?: DataSourceFieldType[];
|
||||||
message?: string;
|
message?: string;
|
||||||
} = {},
|
} = {},
|
||||||
@ -219,19 +218,11 @@ const validateDataSourceFieldPath = (
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
let dsId = options.dataSourceId;
|
const dsId = options.dataSourceId;
|
||||||
let fieldNames = path;
|
|
||||||
|
|
||||||
if (!dsId) {
|
if (!dsId) {
|
||||||
if (!path.length) {
|
// 仅当取值为空数组或首项为空串时命中。表单校验管道里 validateTypeMatch 对空数组会短路,
|
||||||
return defaultMessage(options.message, '值不在可选项中', dataSourceIdSuggestion());
|
// 因此这里只可能来自直接调用 validateDataSourceFieldSelect 的自定义 validator
|
||||||
}
|
return defaultMessage(options.message, '数据源不存在', dataSourceIdSuggestion());
|
||||||
const rawDsId = path[0];
|
|
||||||
dsId =
|
|
||||||
options.valueMode === 'key' || !`${rawDsId}`.startsWith(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX)
|
|
||||||
? `${rawDsId}`
|
|
||||||
: removeDataSourceFieldPrefix(`${rawDsId}`);
|
|
||||||
fieldNames = path.slice(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ds = findDataSource(`${dsId}`);
|
const ds = findDataSource(`${dsId}`);
|
||||||
@ -239,11 +230,11 @@ const validateDataSourceFieldPath = (
|
|||||||
return defaultMessage(options.message, `数据源(${dsId})不存在`, dataSourceIdSuggestion());
|
return defaultMessage(options.message, `数据源(${dsId})不存在`, dataSourceIdSuggestion());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fieldNames.length) {
|
if (!path.length) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { field, ok, fields, failedName } = resolveFieldByPath(ds.fields, fieldNames);
|
const { field, ok, fields, failedName } = resolveFieldByPath(ds.fields, path);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return defaultMessage(
|
return defaultMessage(
|
||||||
options.message,
|
options.message,
|
||||||
@ -258,11 +249,15 @@ const validateDataSourceFieldPath = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const leafType = field?.type || 'any';
|
const leafType = field?.type || 'any';
|
||||||
if (leafType === 'any' || allowedTypes.includes(leafType)) {
|
if (leafType !== 'any' && !allowedTypes.includes(leafType)) {
|
||||||
return undefined;
|
const fieldName = field?.name || path[path.length - 1];
|
||||||
}
|
|
||||||
|
|
||||||
return defaultMessage(options.message, '值不在可选项中', dataSourceIdSuggestion());
|
// 文案已点明当前字段类型与要求类型,无需再列同级可选字段
|
||||||
|
return defaultMessage(
|
||||||
|
options.message,
|
||||||
|
`请选择类型为${allowedTypes.join('或')}的字段,字段(${fieldName})的类型为${leafType}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateDataSourceMethodTuple = (value: any, message?: string): string | undefined => {
|
const validateDataSourceMethodTuple = (value: any, message?: string): string | undefined => {
|
||||||
@ -367,7 +362,7 @@ const validateCondOpSelect: TypeMatchValidator = (value, { message, props }) =>
|
|||||||
const parentFields = props.config?.parentFields || [];
|
const parentFields = props.config?.parentFields || [];
|
||||||
const fieldPath = Array.isArray(props.model?.field) ? props.model.field : [];
|
const fieldPath = Array.isArray(props.model?.field) ? props.model.field : [];
|
||||||
const [id, ...fieldNames] = [...parentFields, ...fieldPath];
|
const [id, ...fieldNames] = [...parentFields, ...fieldPath];
|
||||||
const ds = id ? findDataSource(`${id}`) : undefined;
|
const ds = id ? findDataSource(removeDataSourceFieldPrefix(`${id}`)) : undefined;
|
||||||
const fieldType = getFieldType(ds, fieldNames);
|
const fieldType = getFieldType(ds, fieldNames);
|
||||||
const allowed = getCondOpsByFieldType(fieldType);
|
const allowed = getCondOpsByFieldType(fieldType);
|
||||||
|
|
||||||
@ -464,7 +459,7 @@ export type ValidateDataSourceFieldSelectOptions = {
|
|||||||
/**
|
/**
|
||||||
* data-source-field-select 的 typeMatch 校验逻辑,可供自定义 rules.validator 复用。
|
* data-source-field-select 的 typeMatch 校验逻辑,可供自定义 rules.validator 复用。
|
||||||
*/
|
*/
|
||||||
export const validateDataSourceFieldSelectValue = (
|
export const validateDataSourceFieldSelect = (
|
||||||
value: any,
|
value: any,
|
||||||
context: TypeMatchValidateContext,
|
context: TypeMatchValidateContext,
|
||||||
options?: ValidateDataSourceFieldSelectOptions,
|
options?: ValidateDataSourceFieldSelectOptions,
|
||||||
@ -492,17 +487,22 @@ export const validateDataSourceFieldSelectValue = (
|
|||||||
return defaultMessage(message, `${value}类型应为字符串数组`, dataSourceFieldPathSuggestion());
|
return defaultMessage(message, `${value}类型应为字符串数组`, dataSourceFieldPathSuggestion());
|
||||||
}
|
}
|
||||||
|
|
||||||
return validateDataSourceFieldPath(value, {
|
// 未指定 dataSourceId 时,路径首项为数据源 id,其余为字段名。
|
||||||
dataSourceId: config.dataSourceId,
|
// value 模式的首项带 ds-field:: 前缀、key 模式不带,removeDataSourceFieldPrefix 对后者是幂等的,无需分支。
|
||||||
valueMode: config.value,
|
let dataSourceId = config.dataSourceId ? `${config.dataSourceId}` : undefined;
|
||||||
|
let fieldNames = value;
|
||||||
|
if (!dataSourceId) {
|
||||||
|
dataSourceId = value.length ? removeDataSourceFieldPrefix(value[0]) : undefined;
|
||||||
|
fieldNames = value.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return validateDataSourceFieldPath(fieldNames, {
|
||||||
|
dataSourceId,
|
||||||
dataSourceFieldType: config.dataSourceFieldType,
|
dataSourceFieldType: config.dataSourceFieldType,
|
||||||
message,
|
message,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateDataSourceFieldSelect: TypeMatchValidator = (value, context) =>
|
|
||||||
validateDataSourceFieldSelectValue(value, context);
|
|
||||||
|
|
||||||
const validateDataSourceSelect: TypeMatchValidator = (value, { message, props }) => {
|
const validateDataSourceSelect: TypeMatchValidator = (value, { message, props }) => {
|
||||||
const config = props.config || {};
|
const config = props.config || {};
|
||||||
const dataSources = getDataSources();
|
const dataSources = getDataSources();
|
||||||
@ -678,7 +678,8 @@ export const editorTypeMatchRules: Record<string, TypeMatchValidator> = {
|
|||||||
'ui-select': validateUiSelect,
|
'ui-select': validateUiSelect,
|
||||||
'data-source-input': validateDataSourceInput,
|
'data-source-input': validateDataSourceInput,
|
||||||
'data-source-method-select': validateDataSourceMethodSelect,
|
'data-source-method-select': validateDataSourceMethodSelect,
|
||||||
'data-source-field-select': validateDataSourceFieldSelect,
|
/** 注册进 typeMatch 规则表的入口,收窄为 TypeMatchValidator,避免调用方误传第三个参数 */
|
||||||
|
'data-source-field-select': (value, context) => validateDataSourceFieldSelect(value, context),
|
||||||
'data-source-select': validateDataSourceSelect,
|
'data-source-select': validateDataSourceSelect,
|
||||||
'code-select': validateCodeSelect,
|
'code-select': validateCodeSelect,
|
||||||
'data-source-fields': validateDataSourceFields,
|
'data-source-fields': validateDataSourceFields,
|
||||||
|
|||||||
@ -100,4 +100,14 @@ describe('CondOpSelect', () => {
|
|||||||
await wrapper.findComponent({ name: 'TMagicSelect' }).vm.$emit('change', '=');
|
await wrapper.findComponent({ name: 'TMagicSelect' }).vm.$emit('change', '=');
|
||||||
expect(wrapper.emitted('change')?.[0]?.[0]).toBe('=');
|
expect(wrapper.emitted('change')?.[0]?.[0]).toBe('=');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('字段路径带 ds-field:: 前缀时仍按数据源 id 查询', () => {
|
||||||
|
(getFieldType as any).mockReturnValue('number');
|
||||||
|
mount(CondOpSelect, {
|
||||||
|
props: baseProps({
|
||||||
|
model: { field: ['ds-field::ds1', 'a'], op: '' },
|
||||||
|
}) as any,
|
||||||
|
});
|
||||||
|
expect(dataSourceService.getDataSourceById).toHaveBeenCalledWith('ds1');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -324,4 +324,17 @@ describe('DataSourceFieldSelect Index', () => {
|
|||||||
await toggleBtn.trigger('click');
|
await toggleBtn.trigger('click');
|
||||||
expect(wrapper.findAll('.fake-cascader').length).toBeGreaterThan(0);
|
expect(wrapper.findAll('.fake-cascader').length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('checkStrictly 为函数时从当前字段值解析数据源', () => {
|
||||||
|
const checkStrictly = vi.fn(() => true);
|
||||||
|
mount(DSFSIndex, {
|
||||||
|
props: {
|
||||||
|
config: { checkStrictly },
|
||||||
|
model: { v: ['ds-ds1', 'a'] },
|
||||||
|
name: 'v',
|
||||||
|
} as any,
|
||||||
|
});
|
||||||
|
expect(checkStrictly).toHaveBeenCalled();
|
||||||
|
expect(checkStrictly.mock.calls[0][1].dataSource?.id).toBe('ds1');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|||||||
import { HookCodeType, HookType, NodeType } from '@tmagic/core';
|
import { HookCodeType, HookType, NodeType } from '@tmagic/core';
|
||||||
import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, DATA_SOURCE_SET_DATA_METHOD_NAME } from '@tmagic/utils';
|
import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, DATA_SOURCE_SET_DATA_METHOD_NAME } from '@tmagic/utils';
|
||||||
|
|
||||||
import { ALL_COND_OPS, editorTypeMatchRules, validateDataSourceFieldSelectValue } from '@editor/utils/type-match-rules';
|
import { ALL_COND_OPS, editorTypeMatchRules, validateDataSourceFieldSelect } from '@editor/utils/type-match-rules';
|
||||||
|
|
||||||
const codeDslState = vi.hoisted(() => ({ value: null as Record<string, any> | null }));
|
const codeDslState = vi.hoisted(() => ({ value: null as Record<string, any> | null }));
|
||||||
const dataSourcesState = vi.hoisted(() => ({ value: [] as any[] }));
|
const dataSourcesState = vi.hoisted(() => ({ value: [] as any[] }));
|
||||||
@ -126,6 +126,9 @@ describe('editorTypeMatchRules', () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
expect(run('cond-op-select', '>', {}, { field: ['ds1', 'age'] })).toBeUndefined();
|
expect(run('cond-op-select', '>', {}, { field: ['ds1', 'age'] })).toBeUndefined();
|
||||||
|
expect(
|
||||||
|
run('cond-op-select', '>', {}, { field: [`${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}ds1`, 'age'] }),
|
||||||
|
).toBeUndefined();
|
||||||
expect(firstLine(run('cond-op-select', 'include', {}, { field: ['ds1', 'age'] }))).toBe('include 不在可选项中');
|
expect(firstLine(run('cond-op-select', 'include', {}, { field: ['ds1', 'age'] }))).toBe('include 不在可选项中');
|
||||||
expect(run('cond-op-select', 'is', {}, { field: ['ds1', 'flag'] })).toBeUndefined();
|
expect(run('cond-op-select', 'is', {}, { field: ['ds1', 'flag'] })).toBeUndefined();
|
||||||
// 未知类型与 UI 默认选项对齐:不含 boolean ops
|
// 未知类型与 UI 默认选项对齐:不含 boolean ops
|
||||||
@ -234,6 +237,11 @@ describe('editorTypeMatchRules', () => {
|
|||||||
|
|
||||||
expect(run('data-source-field-select', ['ds1', 'title'], { value: 'key' })).toBeUndefined();
|
expect(run('data-source-field-select', ['ds1', 'title'], { value: 'key' })).toBeUndefined();
|
||||||
expect(run('data-source-field-select', [`${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}ds1`, 'title'])).toBeUndefined();
|
expect(run('data-source-field-select', [`${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}ds1`, 'title'])).toBeUndefined();
|
||||||
|
// 未指定 dataSourceId 且路径为空:缺少数据源 id
|
||||||
|
expect(firstLine(run('data-source-field-select', [], { value: 'key' }))).toBe('数据源不存在');
|
||||||
|
// 已有 dataSourceId 时,空字段路径视为只选了数据源,不报错
|
||||||
|
expect(run('data-source-field-select', [], { dataSourceId: 'ds1' })).toBeUndefined();
|
||||||
|
expect(run('data-source-field-select', ['ds1'], { value: 'key' })).toBeUndefined();
|
||||||
// 数据源不存在时直出具体的数据源 id
|
// 数据源不存在时直出具体的数据源 id
|
||||||
expect(firstLine(run('data-source-field-select', ['missing', 'title'], { value: 'key' }))).toBe(
|
expect(firstLine(run('data-source-field-select', ['missing', 'title'], { value: 'key' }))).toBe(
|
||||||
'数据源(missing)不存在',
|
'数据源(missing)不存在',
|
||||||
@ -254,23 +262,55 @@ describe('editorTypeMatchRules', () => {
|
|||||||
);
|
);
|
||||||
// 父字段无子字段时无建议
|
// 父字段无子字段时无建议
|
||||||
expect(run('data-source-field-select', ['ds1', 'title', 'x'], { value: 'key' })).toBe('数据源字段(x)不存在');
|
expect(run('data-source-field-select', ['ds1', 'title', 'x'], { value: 'key' })).toBe('数据源字段(x)不存在');
|
||||||
|
// 类型不匹配时,文案直出当前字段与其类型,不追加建议
|
||||||
expect(
|
expect(
|
||||||
firstLine(
|
run('data-source-field-select', ['title'], {
|
||||||
run('data-source-field-select', ['title'], {
|
dataSourceId: 'ds1',
|
||||||
dataSourceId: 'ds1',
|
dataSourceFieldType: ['number'],
|
||||||
dataSourceFieldType: ['number'],
|
}),
|
||||||
}),
|
).toBe('请选择类型为number的字段,字段(title)的类型为string');
|
||||||
),
|
|
||||||
).toBe('值不在可选项中');
|
|
||||||
expect(
|
expect(
|
||||||
run('data-source-field-select', ['obj', 'a'], {
|
run('data-source-field-select', ['obj', 'a'], {
|
||||||
dataSourceId: 'ds1',
|
dataSourceId: 'ds1',
|
||||||
dataSourceFieldType: ['number'],
|
dataSourceFieldType: ['number'],
|
||||||
}),
|
}),
|
||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
|
expect(
|
||||||
|
run('data-source-field-select', ['obj', 'a'], {
|
||||||
|
dataSourceId: 'ds1',
|
||||||
|
dataSourceFieldType: ['string'],
|
||||||
|
}),
|
||||||
|
).toBe('请选择类型为string的字段,字段(a)的类型为number');
|
||||||
|
|
||||||
|
// 有 fieldConfig、未声明 value/dataSourceId 时,仍按取值中的 ds-field:: 前缀解析数据源路径
|
||||||
|
dataSourcesState.value = [
|
||||||
|
{
|
||||||
|
id: 'ds_4554243a',
|
||||||
|
type: 'base',
|
||||||
|
fields: [{ name: 'marqueeModId', type: 'string' }],
|
||||||
|
methods: [],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
expect(
|
||||||
|
run('data-source-field-select', [`${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}ds_4554243a`, 'marqueeModId'], {
|
||||||
|
name: 'modId',
|
||||||
|
checkStrictly: false,
|
||||||
|
dataSourceFieldType: ['string'],
|
||||||
|
fieldConfig: { type: 'mod-select', modType: 100119 },
|
||||||
|
}),
|
||||||
|
).toBeUndefined();
|
||||||
|
expect(
|
||||||
|
firstLine(
|
||||||
|
run('data-source-field-select', [`${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}ds_4554243a`, 'missing'], {
|
||||||
|
name: 'modId',
|
||||||
|
dataSourceFieldType: ['string'],
|
||||||
|
fieldConfig: { type: 'mod-select', modType: 100119 },
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
).toBe('数据源字段(missing)不存在');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('validateDataSourceFieldSelectValue 支持自定义 plain 值校验并保留数据源路径校验', () => {
|
test('validateDataSourceFieldSelect 支持自定义 plain 值校验并保留数据源路径校验', () => {
|
||||||
const config = {
|
const config = {
|
||||||
name: 'fontWeight',
|
name: 'fontWeight',
|
||||||
type: 'data-source-field-select',
|
type: 'data-source-field-select',
|
||||||
@ -287,9 +327,9 @@ describe('editorTypeMatchRules', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(validateDataSourceFieldSelectValue(700, context, allowStringOrNumber)).toBeUndefined();
|
expect(validateDataSourceFieldSelect(700, context, allowStringOrNumber)).toBeUndefined();
|
||||||
expect(validateDataSourceFieldSelectValue('bold', context, allowStringOrNumber)).toBeUndefined();
|
expect(validateDataSourceFieldSelect('bold', context, allowStringOrNumber)).toBeUndefined();
|
||||||
expect(firstLine(validateDataSourceFieldSelectValue({ a: 1 }, context, allowStringOrNumber))).toBe(
|
expect(firstLine(validateDataSourceFieldSelect({ a: 1 }, context, allowStringOrNumber))).toBe(
|
||||||
'fontWeight 类型应为字符串或数字',
|
'fontWeight 类型应为字符串或数字',
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -306,7 +346,7 @@ describe('editorTypeMatchRules', () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
validateDataSourceFieldSelectValue(
|
validateDataSourceFieldSelect(
|
||||||
[`${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}ds1`, 'weight'],
|
[`${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}ds1`, 'weight'],
|
||||||
context,
|
context,
|
||||||
allowStringOrNumber,
|
allowStringOrNumber,
|
||||||
@ -314,7 +354,7 @@ describe('editorTypeMatchRules', () => {
|
|||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
expect(
|
expect(
|
||||||
firstLine(
|
firstLine(
|
||||||
validateDataSourceFieldSelectValue(
|
validateDataSourceFieldSelect(
|
||||||
[`${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}ds1`, 'missing'],
|
[`${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}ds1`, 'missing'],
|
||||||
context,
|
context,
|
||||||
allowStringOrNumber,
|
allowStringOrNumber,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user