mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 03:48:13 +08:00
fix: ConditionBuilder使用公式编辑器切换类型异常问题
This commit is contained in:
parent
f210a93d9a
commit
a02a2e3c3e
@ -96,7 +96,9 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
|
||||
|
||||
@autobind
|
||||
handleOperatorChange(op: OperatorType) {
|
||||
const {fields, value, index, onChange} = this.props;
|
||||
const {fields, value, index, onChange, formula} = this.props;
|
||||
const useFormulaInput =
|
||||
formula?.mode === 'input-group' && formula?.inputSettings;
|
||||
const leftFieldSchema: FieldSimple = findTree(
|
||||
fields,
|
||||
(i: FieldSimple) => i.name === (value?.left as ExpressionField)?.field
|
||||
@ -104,7 +106,10 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
|
||||
const result = {
|
||||
...value,
|
||||
op: op,
|
||||
right: value.right ?? leftFieldSchema?.defaultValue
|
||||
/** 使用公式编辑器模式时,因为不同条件下值格式不一致(比如select类型下包含和等于对应的multiple会变化),所以变化条件时需要清空right值 */
|
||||
right: useFormulaInput
|
||||
? leftFieldSchema?.defaultValue
|
||||
: value.right ?? leftFieldSchema?.defaultValue
|
||||
};
|
||||
|
||||
onChange(result, index);
|
||||
|
@ -191,6 +191,15 @@ export class FormulaEditor extends React.Component<
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
try {
|
||||
value = JSON.stringify(value);
|
||||
} catch (error) {
|
||||
console.error('[amis][formula] given value is not a string');
|
||||
value = '';
|
||||
}
|
||||
}
|
||||
|
||||
const varMap: {
|
||||
[propname: string]: string;
|
||||
} = {};
|
||||
|
@ -9,7 +9,8 @@ import {
|
||||
LocaleProps,
|
||||
uncontrollable,
|
||||
findTree,
|
||||
isExpression
|
||||
isExpression,
|
||||
isObject
|
||||
} from 'amis-core';
|
||||
|
||||
import {FormulaEditor, VariableItem} from './Editor';
|
||||
@ -96,9 +97,35 @@ const FormulaInput: React.FC<FormulaInputProps> = props => {
|
||||
if (schemaType === 'boolean') {
|
||||
result = origin.value;
|
||||
} else if (schemaType === 'select') {
|
||||
const {
|
||||
joinValues,
|
||||
extractValue,
|
||||
delimiter,
|
||||
multiple,
|
||||
valueField = 'value'
|
||||
} = inputSettings;
|
||||
|
||||
if (joinValues) {
|
||||
if (multiple) {
|
||||
result = Array.isArray(origin)
|
||||
? origin.map(item => item.value)
|
||||
: origin.value;
|
||||
? (origin.map(item => item[valueField]).join(delimiter) as string)
|
||||
: origin
|
||||
? origin[valueField]
|
||||
: '';
|
||||
} else {
|
||||
result = origin ? origin[valueField] : '';
|
||||
}
|
||||
} else if (extractValue) {
|
||||
if (multiple) {
|
||||
result = Array.isArray(origin)
|
||||
? origin.map(item => item[valueField])
|
||||
: origin
|
||||
? [origin[valueField || 'value']]
|
||||
: [];
|
||||
} else {
|
||||
result = origin ? origin[valueField] : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
onChange?.(result);
|
||||
},
|
||||
@ -123,26 +150,58 @@ const FormulaInput: React.FC<FormulaInputProps> = props => {
|
||||
: cmptValue === item?.value;
|
||||
})
|
||||
: null;
|
||||
let useVariable = !!(isExpression(cmptValue) || targetVariable);
|
||||
|
||||
if (
|
||||
isExpression(cmptValue) ||
|
||||
targetVariable ||
|
||||
(schemaType === 'number' &&
|
||||
cmptValue != null &&
|
||||
typeof cmptValue !== 'number') ||
|
||||
(['date', 'time', 'datetime'].includes(schemaType) &&
|
||||
!moment(cmptValue).isValid()) ||
|
||||
(schemaType === 'select' &&
|
||||
cmptValue != null &&
|
||||
!(inputSettings?.options ?? []).some(
|
||||
(item: any) => item?.value === cmptValue
|
||||
)) ||
|
||||
(schemaType === 'boolean' &&
|
||||
cmptValue != null &&
|
||||
typeof cmptValue !== 'boolean')
|
||||
) {
|
||||
/** 判断value是否为变量,如果是变量,使用ResultBox渲染 */
|
||||
if (!useVariable) {
|
||||
if (schemaType === 'number') {
|
||||
useVariable = cmptValue != null && typeof cmptValue !== 'number';
|
||||
} else if (['date', 'time', 'datetime'].includes(schemaType)) {
|
||||
useVariable = !moment(cmptValue).isValid();
|
||||
} else if (schemaType === 'select') {
|
||||
const {
|
||||
options,
|
||||
joinValues,
|
||||
extractValue,
|
||||
delimiter,
|
||||
multiple,
|
||||
valueField = 'value'
|
||||
} = inputSettings;
|
||||
let selctedValue: any[] = [];
|
||||
|
||||
if (multiple) {
|
||||
if (joinValues) {
|
||||
selctedValue =
|
||||
typeof cmptValue === 'string' ? cmptValue.split(delimiter) : [];
|
||||
} else {
|
||||
selctedValue = Array.isArray(cmptValue)
|
||||
? extractValue
|
||||
? cmptValue
|
||||
: cmptValue.map(i => i?.[valueField])
|
||||
: [];
|
||||
}
|
||||
} else {
|
||||
if (joinValues) {
|
||||
selctedValue = typeof cmptValue === 'string' ? [cmptValue] : [];
|
||||
} else {
|
||||
selctedValue = isObject(cmptValue) ? [cmptValue?.[valueField]] : [];
|
||||
}
|
||||
}
|
||||
|
||||
/** 选项类型清空后是空字符串, */
|
||||
useVariable =
|
||||
cmptValue &&
|
||||
!(options ?? []).some((item: any) =>
|
||||
selctedValue.includes(item?.value)
|
||||
);
|
||||
} else if (schemaType === 'boolean') {
|
||||
useVariable = cmptValue != null && typeof cmptValue !== 'boolean';
|
||||
}
|
||||
}
|
||||
|
||||
if (useVariable) {
|
||||
const varName =
|
||||
cmptValue && mixedMode
|
||||
typeof cmptValue === 'string' && cmptValue && mixedMode
|
||||
? cmptValue.replace(/^\$\{/, '').replace(/\}$/, '')
|
||||
: cmptValue;
|
||||
const resultValue = targetVariable?.value ?? varName;
|
||||
|
@ -14,10 +14,17 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {fireEvent, render, screen, waitFor} from '@testing-library/react';
|
||||
import {fireEvent, render, screen, cleanup, waitFor} from '@testing-library/react';
|
||||
import '../../../src';
|
||||
import {render as amisRender} from '../../../src';
|
||||
import {render as amisRender, clearStoresCache} from '../../../src';
|
||||
import {makeEnv, replaceReactAriaIds, wait} from '../../helper';
|
||||
import { Select } from 'packages/amis-ui/lib/components/Select';
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
clearStoresCache();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
const testSchema = {
|
||||
type: 'page',
|
||||
@ -801,3 +808,341 @@ test('Renderer:condition-builder with not embed', async () => {
|
||||
baseElement.querySelector('.cxd-Modal .cxd-CBGroup')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
/**
|
||||
* 组合条件使用公式编辑器
|
||||
* 1. 7种类型的公式编辑器正常渲染
|
||||
* 2. 选项类型(select)字段,切换操作符(包含 -> 等于),字段值清空且正常渲染(等于和包含对应的multiple不一样,所以值格式不一样)
|
||||
* 3. 先使用其他类型字段,再切换到select类型,条件选择包含,值正常渲染
|
||||
*/
|
||||
describe.only('Renderer: condition-builder with formula', () => {
|
||||
const onSubmit = jest.fn();
|
||||
test('condition-builder with different fields', async () => {
|
||||
const {container} = render(amisRender({
|
||||
"type": "form",
|
||||
"data": {
|
||||
"conditions": {
|
||||
"id": "68bddc1495e9",
|
||||
"conjunction": "and",
|
||||
"children": [
|
||||
{
|
||||
"id": "b9cc34dae93a",
|
||||
"left": {
|
||||
"type": "field",
|
||||
"field": "text"
|
||||
},
|
||||
"op": "equal"
|
||||
},
|
||||
{
|
||||
"id": "4c718986c321",
|
||||
"left": {
|
||||
"type": "field",
|
||||
"field": "number"
|
||||
},
|
||||
"op": "equal"
|
||||
},
|
||||
{
|
||||
"id": "7ee79c416422",
|
||||
"left": {
|
||||
"type": "field",
|
||||
"field": "boolean"
|
||||
},
|
||||
"op": "equal"
|
||||
},
|
||||
{
|
||||
"id": "9cd76d8a6522",
|
||||
"left": {
|
||||
"type": "field",
|
||||
"field": "select"
|
||||
},
|
||||
"op": "select_equals"
|
||||
},
|
||||
{
|
||||
"id": "20a65e9df546",
|
||||
"left": {
|
||||
"type": "field",
|
||||
"field": "date"
|
||||
},
|
||||
"op": "equal"
|
||||
},
|
||||
{
|
||||
"id": "e729b32ea9e8",
|
||||
"left": {
|
||||
"type": "field",
|
||||
"field": "time"
|
||||
},
|
||||
"op": "equal"
|
||||
},
|
||||
{
|
||||
"id": "a5f48e000557",
|
||||
"left": {
|
||||
"type": "field",
|
||||
"field": "datetime"
|
||||
},
|
||||
"op": "equal"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "condition-builder",
|
||||
"label": "条件组件",
|
||||
"name": "conditions",
|
||||
"searchable": true,
|
||||
"formula": {
|
||||
"mode": "input-group",
|
||||
"inputSettings": {},
|
||||
"allowInput": true,
|
||||
"mixedMode": true,
|
||||
"variables": []
|
||||
},
|
||||
"fields": [
|
||||
{
|
||||
"label": "文本",
|
||||
"type": "text",
|
||||
"name": "text"
|
||||
},
|
||||
{
|
||||
"label": "数字",
|
||||
"type": "number",
|
||||
"name": "number"
|
||||
},
|
||||
{
|
||||
"label": "布尔",
|
||||
"type": "boolean",
|
||||
"name": "boolean"
|
||||
},
|
||||
{
|
||||
"label": "选项",
|
||||
"type": "select",
|
||||
"name": "select",
|
||||
"options": [
|
||||
{
|
||||
"label": "A",
|
||||
"value": "a"
|
||||
},
|
||||
{
|
||||
"label": "B",
|
||||
"value": "b"
|
||||
},
|
||||
{
|
||||
"label": "C",
|
||||
"value": "c"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "日期",
|
||||
"children": [
|
||||
{
|
||||
"label": "日期",
|
||||
"type": "date",
|
||||
"name": "date"
|
||||
},
|
||||
{
|
||||
"label": "时间",
|
||||
"type": "time",
|
||||
"name": "time"
|
||||
},
|
||||
{
|
||||
"label": "日期时间",
|
||||
"type": "datetime",
|
||||
"name": "datetime"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}, {onSubmit}, makeEnv({})));
|
||||
|
||||
replaceReactAriaIds(container);
|
||||
// 7种类型都存在
|
||||
expect(container.querySelectorAll('.cxd-FormulaPicker-input')?.length).toEqual(7);
|
||||
expect(container.querySelector('.cxd-FormulaPicker--text')).toBeInTheDocument();
|
||||
expect(container.querySelector('.cxd-FormulaPicker-input-number')).toBeInTheDocument();
|
||||
expect(container.querySelector('.cxd-FormulaPicker-input-boolean')).toBeInTheDocument();
|
||||
expect(container.querySelector('.cxd-FormulaPicker-input-select')).toBeInTheDocument();
|
||||
expect(container.querySelector('.cxd-FormulaPicker-input-date')).toBeInTheDocument();
|
||||
expect(container.querySelector('.cxd-FormulaPicker-input-time')).toBeInTheDocument();
|
||||
expect(container.querySelector('.cxd-FormulaPicker-input-datetime')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('condition-builder with select field and change operator', async () => {
|
||||
const {container, findByText} = render(amisRender({
|
||||
"type": "form",
|
||||
"data": {
|
||||
"conditions": {
|
||||
"id": "68bddc1495e9",
|
||||
"conjunction": "and",
|
||||
"children": [
|
||||
{
|
||||
"id": "9cd76d8a6522",
|
||||
"left": {
|
||||
"type": "field",
|
||||
"field": "select"
|
||||
},
|
||||
"op": "select_equals"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "condition-builder",
|
||||
"label": "条件组件",
|
||||
"name": "conditions",
|
||||
"searchable": true,
|
||||
"formula": {
|
||||
"mode": "input-group",
|
||||
"inputSettings": {},
|
||||
"allowInput": true,
|
||||
"mixedMode": true,
|
||||
"variables": []
|
||||
},
|
||||
"fields": [
|
||||
{
|
||||
"label": "选项",
|
||||
"type": "select",
|
||||
"name": "select",
|
||||
"options": [
|
||||
{
|
||||
"label": "A",
|
||||
"value": "a"
|
||||
},
|
||||
{
|
||||
"label": "B",
|
||||
"value": "b"
|
||||
},
|
||||
{
|
||||
"label": "C",
|
||||
"value": "c"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}, {}, makeEnv({})));
|
||||
|
||||
replaceReactAriaIds(container);
|
||||
|
||||
// 选中第一个选项(Form中默认值是等于操作)
|
||||
let fieldValueControl = container.querySelector('.cxd-FormulaPicker-input-select')!;
|
||||
fireEvent.click(fieldValueControl);
|
||||
await wait(100);
|
||||
fireEvent.click(await findByText('A'));
|
||||
expect(container.querySelector('.cxd-Tag-text')?.innerHTML).toEqual('A');
|
||||
|
||||
// 切换操作符,字段值清空,需要重新选择,且下拉选项变成多选
|
||||
const opControl = container.querySelector('.cxd-CBGroup-operatorInput')!;
|
||||
fireEvent.click(opControl);
|
||||
await wait(100);
|
||||
fireEvent.click(await findByText('包含'));
|
||||
await wait(100);
|
||||
expect(container.querySelector('.cxd-Select-placeholder')).toBeInTheDocument();
|
||||
fieldValueControl = container.querySelector('.cxd-FormulaPicker-input-select')!;
|
||||
fireEvent.click(fieldValueControl);
|
||||
await wait(100);
|
||||
expect(container.querySelectorAll('.cxd-Select-option-checkbox').length).toEqual(3);
|
||||
});
|
||||
|
||||
test('condition-builder with field type change', async () => {
|
||||
const onSubmit = jest.fn();
|
||||
const {container, findByText, findByPlaceholderText} = render(amisRender({
|
||||
"type": "form",
|
||||
"data": {
|
||||
"conditions": {
|
||||
"id": "68bddc1495e9",
|
||||
"conjunction": "and",
|
||||
"children": [
|
||||
{
|
||||
"id": "b9cc34dae93a",
|
||||
"left": {
|
||||
"type": "field",
|
||||
"field": "text"
|
||||
},
|
||||
"op": "equal"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "condition-builder",
|
||||
"label": "条件组件",
|
||||
"name": "conditions",
|
||||
"searchable": true,
|
||||
"formula": {
|
||||
"mode": "input-group",
|
||||
"inputSettings": {},
|
||||
"allowInput": true,
|
||||
"mixedMode": true,
|
||||
"variables": []
|
||||
},
|
||||
"fields": [
|
||||
{
|
||||
"label": "文本",
|
||||
"type": "text",
|
||||
"name": "text"
|
||||
},
|
||||
{
|
||||
"label": "选项",
|
||||
"type": "select",
|
||||
"name": "select",
|
||||
"options": [
|
||||
{
|
||||
"label": "A",
|
||||
"value": "a"
|
||||
},
|
||||
{
|
||||
"label": "B",
|
||||
"value": "b"
|
||||
},
|
||||
{
|
||||
"label": "C",
|
||||
"value": "c"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}, {onSubmit}, makeEnv({})));
|
||||
|
||||
replaceReactAriaIds(container);
|
||||
|
||||
// 切换字段类型,对应字段值控件更新
|
||||
const fieldControl = container.querySelector('.cxd-DropDownSelection-input')!;
|
||||
fireEvent.click(fieldControl);
|
||||
await wait(100);
|
||||
fireEvent.click(await findByText('选项'));
|
||||
await wait(100);
|
||||
let selectValueControl = container.querySelector('.cxd-FormulaPicker-input-select')!;
|
||||
expect(selectValueControl).toBeInTheDocument();
|
||||
|
||||
// 切换操作符,下拉选项变成多选
|
||||
const opControl = container.querySelector('.cxd-CBGroup-operatorInput')!;
|
||||
fireEvent.click(opControl);
|
||||
await wait(100);
|
||||
fireEvent.click(await findByText('包含'));
|
||||
await wait(100);
|
||||
expect(container.querySelector('.cxd-Select-placeholder')).toBeInTheDocument();
|
||||
selectValueControl = container.querySelector('.cxd-FormulaPicker-input-select')!;
|
||||
fireEvent.click(selectValueControl);
|
||||
await wait(100);
|
||||
expect(container.querySelectorAll('.cxd-Select-option-checkbox').length).toEqual(3);
|
||||
|
||||
// 选择2个选项,绑定值变化
|
||||
fireEvent.click(await findByText('A'));
|
||||
fireEvent.click(await findByText('C'));
|
||||
const selectedValues = [];
|
||||
const nodes = container.querySelectorAll('.cxd-Select-valueLabel');
|
||||
for (const el of nodes.values()) {
|
||||
selectedValues.push(el?.innerHTML);
|
||||
}
|
||||
expect(selectedValues.length).toEqual(2);
|
||||
expect(selectedValues.join(',')).toEqual('A,C');
|
||||
});
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user