补充条件组合逻辑

This commit is contained in:
liaoxuezhi 2020-08-18 23:16:55 +08:00
parent 0e78191ddc
commit 5a8c2d8fee
8 changed files with 77 additions and 127 deletions

View File

@ -1,74 +1,3 @@
import React from 'react';
import ConditionBuilder from '../../../src/components/condition-builder';
const fields = [
{
label: '姓名',
name: 'name',
type: 'text'
},
{
label: '年龄',
name: 'age',
type: 'number'
},
{
label: '出生日期',
name: 'birthday',
type: 'date'
},
{
label: '起床时间',
name: 'wakeupAt',
type: 'time'
},
{
label: '入职时间',
name: 'ruzhi',
type: 'datetime'
},
{
label: '关系字段',
children: [
{
label: '姓名',
name: 'name2',
type: 'text'
},
{
label: '年龄',
name: 'age2',
type: 'number'
}
]
}
];
const funcs = [
// {
// label: '',
// children: [
// {
// type: 'LOWERCASE',
// label: '',
// returnType: 'text',
// args: [
// {
// type: 'text',
// label: ''
// }
// ]
// }
// ]
// }
];
export default { export default {
type: 'page', type: 'page',
title: '表单页面', title: '表单页面',
@ -76,50 +5,19 @@ export default {
type: 'form', type: 'form',
mode: 'horizontal', mode: 'horizontal',
title: '', title: '',
data: {a: [{b: 1, c: [{d: 2}]}]}, debug: true,
// debug: true,
api: '/api/mock2/form/saveForm', api: '/api/mock2/form/saveForm',
controls: [ controls: [
// { {
// label: 'Name', label: 'Name',
// type: 'text', type: 'text',
// name: 'name' name: 'name'
// }, },
// {
// label: 'Email',
// type: 'email',
// name: 'email'
// },
// {
// name: 'a',
// type: 'static',
// tpl: '${a|json:2}'
// },
// {
// name: 'a.0.b',
// type: 'text',
// label: 'B'
// },
// {
// name: 'a.0.c.0.d',
// type: 'number',
// label: 'D'
// },
{ {
name: 'a', label: 'Email',
component: ({value, onChange}) => ( type: 'email',
<ConditionBuilder name: 'email'
value={value}
onChange={onChange}
fields={fields}
funcs={funcs}
/>
)
} }
] ]
} }

View File

@ -31,6 +31,10 @@
transition: opacity 0.2s; transition: opacity 0.2s;
display: flex; display: flex;
align-items: center; align-items: center;
.#{$ns}CBDelete {
margin-left: $gap-xs;
}
} }
&:not(:hover) .#{$ns}CBGroup-toolbarRight { &:not(:hover) .#{$ns}CBGroup-toolbarRight {
opacity: 0; opacity: 0;
@ -168,7 +172,7 @@
flex-grow: 1; flex-grow: 1;
} }
&:hover { &:hover > &-body {
background-color: rgba(0, 0, 0, 0.05); background-color: rgba(0, 0, 0, 0.05);
} }

View File

@ -6,7 +6,8 @@ import {
ExpressionFunc, ExpressionFunc,
Type, Type,
FieldSimple, FieldSimple,
FieldGroup FieldGroup,
OperatorType
} from './types'; } from './types';
import React from 'react'; import React from 'react';
import ConditionField from './Field'; import ConditionField from './Field';
@ -34,6 +35,7 @@ export interface ExpressionProps extends ThemeProps {
funcs?: Funcs; funcs?: Funcs;
defaultType?: 'value' | 'field' | 'func' | 'raw'; defaultType?: 'value' | 'field' | 'func' | 'raw';
allowedTypes?: Array<'value' | 'field' | 'func' | 'raw'>; allowedTypes?: Array<'value' | 'field' | 'func' | 'raw'>;
op?: OperatorType;
} }
const fieldMap = { const fieldMap = {
@ -109,7 +111,8 @@ export class Expression extends React.Component<ExpressionProps> {
defaultType, defaultType,
allowedTypes, allowedTypes,
funcs, funcs,
fields fields,
op
} = this.props; } = this.props;
const inputType = const inputType =
((value as any)?.type === 'field' ((value as any)?.type === 'field'
@ -138,6 +141,7 @@ export class Expression extends React.Component<ExpressionProps> {
field={valueField!} field={valueField!}
value={value} value={value}
onChange={this.handleValueChange} onChange={this.handleValueChange}
op={op}
/> />
) : null} ) : null}

View File

@ -158,11 +158,7 @@ export class ConditionGroup extends React.Component<ConditionGroupProps> {
<Icon icon="plus" className="icon" /> <Icon icon="plus" className="icon" />
</Button> </Button>
<Button <Button onClick={this.handleAddGroup} size="xs">
onClick={this.handleAddGroup}
size="xs"
className="m-r-xs"
>
<Icon icon="plus-cicle" className="icon" /> <Icon icon="plus-cicle" className="icon" />
</Button> </Button>

View File

@ -95,7 +95,7 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
} }
renderLeft() { renderLeft() {
const {value, fields, funcs} = this.props; const {value, fields, funcs, config} = this.props;
return ( return (
<Expression <Expression
@ -104,7 +104,9 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
onChange={this.handleLeftChange} onChange={this.handleLeftChange}
fields={fields} fields={fields}
defaultType="field" defaultType="field"
allowedTypes={['field', 'func']} allowedTypes={(config.valueTypes || ['field', 'func']).filter(
type => type === 'field' || type === 'func'
)}
/> />
); );
} }
@ -272,13 +274,17 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
return ( return (
<Expression <Expression
op={op}
funcs={funcs} funcs={funcs}
valueField={field} valueField={field}
value={value.right} value={value.right}
onChange={this.handleRightChange} onChange={this.handleRightChange}
fields={fields} fields={fields}
defaultType="value" defaultType="value"
allowedTypes={field?.valueTypes || ['value', 'field', 'func', 'raw']} allowedTypes={
field?.valueTypes ||
config.valueTypes || ['value', 'field', 'func', 'raw']
}
/> />
); );
} }

View File

@ -1,19 +1,22 @@
import React from 'react'; import React from 'react';
import {FieldSimple} from './types'; import {FieldSimple, OperatorType} from './types';
import {ThemeProps, themeable} from '../../theme'; import {ThemeProps, themeable} from '../../theme';
import InputBox from '../InputBox'; import InputBox from '../InputBox';
import NumberInput from '../NumberInput'; import NumberInput from '../NumberInput';
import DatePicker from '../DatePicker'; import DatePicker from '../DatePicker';
import Select from '../Select';
import Switch from '../Switch';
export interface ValueProps extends ThemeProps { export interface ValueProps extends ThemeProps {
value: any; value: any;
onChange: (value: any) => void; onChange: (value: any) => void;
field: FieldSimple; field: FieldSimple;
op?: OperatorType;
} }
export class Value extends React.Component<ValueProps> { export class Value extends React.Component<ValueProps> {
render() { render() {
const {classnames: cx, field, value, onChange} = this.props; const {classnames: cx, field, value, onChange, op} = this.props;
let input: JSX.Element | undefined = undefined; let input: JSX.Element | undefined = undefined;
if (field.type === 'text') { if (field.type === 'text') {
@ -27,7 +30,7 @@ export class Value extends React.Component<ValueProps> {
} else if (field.type === 'number') { } else if (field.type === 'number') {
input = ( input = (
<NumberInput <NumberInput
placeholder={field.placeholder || '请选择日期'} placeholder={field.placeholder || '请输入数字'}
min={field.minimum} min={field.minimum}
max={field.maximum} max={field.maximum}
value={value ?? field.defaultValue} value={value ?? field.defaultValue}
@ -69,6 +72,20 @@ export class Value extends React.Component<ValueProps> {
timeFormat={field.timeFormat || 'HH:mm'} timeFormat={field.timeFormat || 'HH:mm'}
/> />
); );
} else if (field.type === 'select') {
input = (
<Select
simpleValue
options={field.options!}
value={value ?? field.defaultValue}
onChange={onChange}
multiple={op === 'select_any_in' || op === 'select_not_any_in'}
/>
);
} else if (field.type === 'boolean') {
input = (
<Switch value={value ?? field.defaultValue} onChange={onChange} />
);
} }
return <div className={cx('CBValue')}>{input}</div>; return <div className={cx('CBValue')}>{input}</div>;

View File

@ -5,6 +5,7 @@ export interface BaseFieldConfig {
} }
export interface Config { export interface Config {
valueTypes?: Array<'value' | 'field' | 'func' | 'raw'>;
fields: Fields; fields: Fields;
funcs?: Funcs; funcs?: Funcs;
maxLevel?: number; maxLevel?: number;
@ -27,10 +28,15 @@ export const OperationMap = {
like: '模糊匹配', like: '模糊匹配',
not_like: '不匹配', not_like: '不匹配',
starts_with: '匹配开头', starts_with: '匹配开头',
ends_with: '匹配结尾' ends_with: '匹配结尾',
select_equals: '等于',
select_not_equals: '不等于',
select_any_in: '包含',
select_not_any_in: '不包含'
}; };
const defaultConfig: Config = { const defaultConfig: Config = {
valueTypes: ['value'],
types: { types: {
text: { text: {
placeholder: '请输入文本', placeholder: '请输入文本',
@ -103,6 +109,20 @@ const defaultConfig: Config = {
'is_empty', 'is_empty',
'is_not_empty' 'is_not_empty'
] ]
},
select: {
operators: [
'select_equals',
'select_not_equals',
'select_any_in',
'select_not_any_in'
],
valueTypes: ['value']
},
boolean: {
operators: ['equal', 'not_equal']
} }
}, },

View File

@ -21,7 +21,11 @@ export type OperatorType =
| 'greater' | 'greater'
| 'greater_or_equal' | 'greater_or_equal'
| 'between' | 'between'
| 'not_between'; | 'not_between'
| 'select_equals'
| 'select_not_equals'
| 'select_any_in'
| 'select_not_any_in';
export type FieldItem = { export type FieldItem = {
type: 'text'; type: 'text';
@ -180,4 +184,5 @@ export type Type = {
defaultOp?: OperatorType; defaultOp?: OperatorType;
operators: Array<OperatorType>; operators: Array<OperatorType>;
placeholder?: string; placeholder?: string;
valueTypes?: Array<'value' | 'field' | 'func' | 'raw'>;
}; };