diff --git a/scss/components/_condition-builder.scss b/scss/components/_condition-builder.scss index 40084124e..05cbd2b86 100644 --- a/scss/components/_condition-builder.scss +++ b/scss/components/_condition-builder.scss @@ -52,16 +52,16 @@ &-fieldCaret, &-operatorCaret { transition: transform 0.3s ease-out; - margin: 3px; + margin: 5px; display: flex; - color: $icon-color; + color: $Form-select-caret-iconColor; &:hover { - color: $icon-onHover-color; + color: $Form-select-caret-onHover-iconColor; } > svg { - width: px2rem(12px); - height: px2rem(12px); + width: px2rem(10px); + height: px2rem(10px); top: 0; } } @@ -267,6 +267,25 @@ margin: px2rem(3px); } +.#{$ns}CBFormula { + position: relative; + display: inline-block; + vertical-align: middle; + margin: px2rem(3px); + + &-label { + background: $ResultBox-value-bg; + color: $text--muted-color; + display: block; + font-size: $fontSizeSm; + align-self: center; + margin: -5px 0 -5px -8px; + padding: 5px; + border-radius: 5px; + user-select: none; + } +} + .#{$ns}CBSeprator { width: 20px; text-align: center; diff --git a/src/components/condition-builder/Expression.tsx b/src/components/condition-builder/Expression.tsx index e407fa57d..f464ffc33 100644 --- a/src/components/condition-builder/Expression.tsx +++ b/src/components/condition-builder/Expression.tsx @@ -16,6 +16,9 @@ import Value from './Value'; import InputSwitch from './InputSwitch'; import ConditionFunc from './Func'; import {ThemeProps, themeable} from '../../theme'; +import {Config} from './config'; +import InputBox from '../InputBox'; +import Formula from './Formula'; /** * 支持4中表达式设置方式 @@ -33,21 +36,22 @@ export interface ExpressionProps extends ThemeProps { valueField?: FieldSimple; fields?: Field[]; funcs?: Funcs; - defaultType?: 'value' | 'field' | 'func' | 'raw'; - allowedTypes?: Array<'value' | 'field' | 'func' | 'raw'>; + defaultType?: 'value' | 'field' | 'func' | 'formula'; + allowedTypes?: Array<'value' | 'field' | 'func' | 'formula'>; op?: OperatorType; + config: Config; } const fieldMap = { value: '值', field: '字段', func: '函数', - raw: '公式' + formula: '公式' }; export class Expression extends React.Component { @autobind - handleInputTypeChange(type: 'value' | 'field' | 'func' | 'raw') { + handleInputTypeChange(type: 'value' | 'field' | 'func' | 'formula') { let value = this.props.value; const onChange = this.props.onChange; @@ -65,9 +69,9 @@ export class Expression extends React.Component { type: 'field', field: '' }; - } else if (type === 'raw') { + } else if (type === 'formula') { value = { - type: 'raw', + type: 'formula', value: '' }; } @@ -102,7 +106,15 @@ export class Expression extends React.Component { } @autobind - handleRawChange() {} + handleFormulaChange(formula: string) { + let value = this.props.value; + const onChange = this.props.onChange; + value = { + type: 'formula', + value: formula + }; + onChange(value, this.props.index); + } render() { const { @@ -112,15 +124,16 @@ export class Expression extends React.Component { allowedTypes, funcs, fields, - op + op, + classnames: cx } = this.props; const inputType = ((value as any)?.type === 'field' ? 'field' : (value as any)?.type === 'func' ? 'func' - : (value as any)?.type === 'raw' - ? 'raw' + : (value as any)?.type === 'formula' + ? 'formula' : value !== undefined ? 'value' : undefined) || @@ -173,6 +186,13 @@ export class Expression extends React.Component { /> ) : null} + {inputType === 'formula' ? ( + + ) : null} + {types.length > 1 ? ( void; +} + +export class Formula extends React.Component { + render() { + const {classnames: cx, value, onChange} = this.props; + + return ( +
+ 公式} + /> +
+ ); + } +} + +export default themeable(Formula); diff --git a/src/components/condition-builder/Func.tsx b/src/components/condition-builder/Func.tsx index 685717b54..8e4ecc37b 100644 --- a/src/components/condition-builder/Func.tsx +++ b/src/components/condition-builder/Func.tsx @@ -13,8 +13,8 @@ export interface ConditionFuncProps extends ThemeProps { onChange: (value: ExpressionFunc) => void; fields?: Field[]; funcs?: Funcs; - defaultType?: 'value' | 'field' | 'func' | 'raw'; - allowedTypes?: Array<'value' | 'field' | 'func' | 'raw'>; + defaultType?: 'value' | 'field' | 'func' | 'formula'; + allowedTypes?: Array<'value' | 'field' | 'func' | 'formula'>; } const option2value = (item: Func) => item.type; diff --git a/src/components/condition-builder/Item.tsx b/src/components/condition-builder/Item.tsx index c18961cd8..4efebfe54 100644 --- a/src/components/condition-builder/Item.tsx +++ b/src/components/condition-builder/Item.tsx @@ -99,6 +99,7 @@ export class ConditionItem extends React.Component { return ( { return ( <> )?.[0]} @@ -252,13 +254,14 @@ export class ConditionItem extends React.Component { defaultType="value" allowedTypes={ field?.valueTypes || - config.valueTypes || ['value', 'field', 'func', 'raw'] + config.valueTypes || ['value', 'field', 'func', 'formula'] } /> ~ )?.[1]} @@ -267,7 +270,7 @@ export class ConditionItem extends React.Component { defaultType="value" allowedTypes={ field?.valueTypes || - config.valueTypes || ['value', 'field', 'func', 'raw'] + config.valueTypes || ['value', 'field', 'func', 'formula'] } /> @@ -276,6 +279,7 @@ export class ConditionItem extends React.Component { return ( { defaultType="value" allowedTypes={ field?.valueTypes || - config.valueTypes || ['value', 'field', 'func', 'raw'] + config.valueTypes || ['value', 'field', 'func', 'formula'] } /> ); diff --git a/src/components/condition-builder/config.ts b/src/components/condition-builder/config.ts index ea5540269..8def53d23 100644 --- a/src/components/condition-builder/config.ts +++ b/src/components/condition-builder/config.ts @@ -5,10 +5,14 @@ export interface BaseFieldConfig { } export interface Config { - valueTypes?: Array<'value' | 'field' | 'func' | 'raw'>; + valueTypes?: Array<'value' | 'field' | 'func' | 'formula'>; fields?: Fields; funcs?: Funcs; maxLevel?: number; // 还没实现 + + // todo 起码需要支持 formula 组件可以自定义。 + + // todo 很多还不能配置。 types: { [propName: string]: Type; }; diff --git a/src/components/condition-builder/index.tsx b/src/components/condition-builder/index.tsx index 14c2f2103..35bf0d757 100644 --- a/src/components/condition-builder/index.tsx +++ b/src/components/condition-builder/index.tsx @@ -4,7 +4,7 @@ import {LocaleProps, localeable} from '../../locale'; import {uncontrollable} from 'uncontrollable'; import {Fields, ConditionGroupValue, Funcs} from './types'; import ConditionGroup from './Group'; -import defaultConfig from './config'; +import defaultConfig, {Config} from './config'; import {autobind, findTreeIndex, spliceTree, getTree} from '../../utils/helper'; import {findDOMNode} from 'react-dom'; import animtion from '../../utils/Animation'; @@ -15,10 +15,11 @@ export interface ConditionBuilderProps extends ThemeProps, LocaleProps { showNot?: boolean; value?: ConditionGroupValue; onChange: (value: ConditionGroupValue) => void; + config?: Config; } export class QueryBuilder extends React.Component { - config = defaultConfig; + config = {...defaultConfig, ...this.props.config}; dragTarget?: HTMLElement; // dragNextSibling: Element | null; diff --git a/src/components/condition-builder/types.ts b/src/components/condition-builder/types.ts index 570b63735..7cf1f6f5c 100644 --- a/src/components/condition-builder/types.ts +++ b/src/components/condition-builder/types.ts @@ -48,8 +48,8 @@ export type ExpressionField = { type: 'field'; field: string; }; -export type ExpressionRaw = { - type: 'raw'; +export type ExpressionFormula = { + type: 'formula'; value: string; }; @@ -57,7 +57,7 @@ export type ExpressionComplex = | ExpressionValue | ExpressionFunc | ExpressionField - | ExpressionRaw; + | ExpressionFormula; export interface ConditionRule { id: any; @@ -78,7 +78,7 @@ export interface ConditionValue extends ConditionGroupValue {} interface BaseField { type: FieldTypes; label: string; - valueTypes?: Array<'value' | 'field' | 'func' | 'raw'>; + valueTypes?: Array<'value' | 'field' | 'func' | 'formula'>; operators?: Array; // valueTypes 里面配置 func 才有效。 @@ -184,5 +184,5 @@ export type Type = { defaultOp?: OperatorType; operators: Array; placeholder?: string; - valueTypes?: Array<'value' | 'field' | 'func' | 'raw'>; + valueTypes?: Array<'value' | 'field' | 'func' | 'formula'>; }; diff --git a/src/renderers/Form/Text.tsx b/src/renderers/Form/Text.tsx index 06a81babf..bdbf92124 100644 --- a/src/renderers/Form/Text.tsx +++ b/src/renderers/Form/Text.tsx @@ -483,7 +483,7 @@ export default class TextControl extends React.PureComponent< (option: any) => !~selectedItem.indexOf(option.value) ); - if (creatable !== false && this.state.inputValue) { + if (!filtedOptions.length && this.state.inputValue) { filtedOptions.push({ [labelField || 'label']: this.state.inputValue, [valueField || 'value']: this.state.inputValue, @@ -578,7 +578,7 @@ export default class TextControl extends React.PureComponent< 'is-disabled': option.disabled }) })} - key={option.value} + key={`${option.label}-${option.value}`} > {option.isNew ? (