还原 text 的 creatable 逻辑

Change-Id: Ibb1421e7016678636a581bf0ed1ea903fa1d8135
This commit is contained in:
2betop 2020-11-02 19:17:56 +08:00
parent 8da0be9128
commit 1cdaa6b763
9 changed files with 105 additions and 30 deletions

View File

@ -52,16 +52,16 @@
&-fieldCaret, &-fieldCaret,
&-operatorCaret { &-operatorCaret {
transition: transform 0.3s ease-out; transition: transform 0.3s ease-out;
margin: 3px; margin: 5px;
display: flex; display: flex;
color: $icon-color; color: $Form-select-caret-iconColor;
&:hover { &:hover {
color: $icon-onHover-color; color: $Form-select-caret-onHover-iconColor;
} }
> svg { > svg {
width: px2rem(12px); width: px2rem(10px);
height: px2rem(12px); height: px2rem(10px);
top: 0; top: 0;
} }
} }
@ -267,6 +267,25 @@
margin: px2rem(3px); 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 { .#{$ns}CBSeprator {
width: 20px; width: 20px;
text-align: center; text-align: center;

View File

@ -16,6 +16,9 @@ import Value from './Value';
import InputSwitch from './InputSwitch'; import InputSwitch from './InputSwitch';
import ConditionFunc from './Func'; import ConditionFunc from './Func';
import {ThemeProps, themeable} from '../../theme'; import {ThemeProps, themeable} from '../../theme';
import {Config} from './config';
import InputBox from '../InputBox';
import Formula from './Formula';
/** /**
* 4 * 4
@ -33,21 +36,22 @@ export interface ExpressionProps extends ThemeProps {
valueField?: FieldSimple; valueField?: FieldSimple;
fields?: Field[]; fields?: Field[];
funcs?: Funcs; funcs?: Funcs;
defaultType?: 'value' | 'field' | 'func' | 'raw'; defaultType?: 'value' | 'field' | 'func' | 'formula';
allowedTypes?: Array<'value' | 'field' | 'func' | 'raw'>; allowedTypes?: Array<'value' | 'field' | 'func' | 'formula'>;
op?: OperatorType; op?: OperatorType;
config: Config;
} }
const fieldMap = { const fieldMap = {
value: '值', value: '值',
field: '字段', field: '字段',
func: '函数', func: '函数',
raw: '公式' formula: '公式'
}; };
export class Expression extends React.Component<ExpressionProps> { export class Expression extends React.Component<ExpressionProps> {
@autobind @autobind
handleInputTypeChange(type: 'value' | 'field' | 'func' | 'raw') { handleInputTypeChange(type: 'value' | 'field' | 'func' | 'formula') {
let value = this.props.value; let value = this.props.value;
const onChange = this.props.onChange; const onChange = this.props.onChange;
@ -65,9 +69,9 @@ export class Expression extends React.Component<ExpressionProps> {
type: 'field', type: 'field',
field: '' field: ''
}; };
} else if (type === 'raw') { } else if (type === 'formula') {
value = { value = {
type: 'raw', type: 'formula',
value: '' value: ''
}; };
} }
@ -102,7 +106,15 @@ export class Expression extends React.Component<ExpressionProps> {
} }
@autobind @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() { render() {
const { const {
@ -112,15 +124,16 @@ export class Expression extends React.Component<ExpressionProps> {
allowedTypes, allowedTypes,
funcs, funcs,
fields, fields,
op op,
classnames: cx
} = this.props; } = this.props;
const inputType = const inputType =
((value as any)?.type === 'field' ((value as any)?.type === 'field'
? 'field' ? 'field'
: (value as any)?.type === 'func' : (value as any)?.type === 'func'
? 'func' ? 'func'
: (value as any)?.type === 'raw' : (value as any)?.type === 'formula'
? 'raw' ? 'formula'
: value !== undefined : value !== undefined
? 'value' ? 'value'
: undefined) || : undefined) ||
@ -173,6 +186,13 @@ export class Expression extends React.Component<ExpressionProps> {
/> />
) : null} ) : null}
{inputType === 'formula' ? (
<Formula
value={(value as any).value}
onChange={this.handleFormulaChange}
/>
) : null}
{types.length > 1 ? ( {types.length > 1 ? (
<InputSwitch <InputSwitch
value={inputType} value={inputType}

View File

@ -0,0 +1,27 @@
import React from 'react';
import {ThemeProps, themeable} from '../../theme';
import InputBox from '../InputBox';
export interface FormulaProps extends ThemeProps {
value: any;
onChange: (value: any) => void;
}
export class Formula extends React.Component<FormulaProps> {
render() {
const {classnames: cx, value, onChange} = this.props;
return (
<div className={cx('CBFormula')}>
<InputBox
value={(value as any).value}
onChange={onChange}
placeholder="请输入公式"
prefix={<span className={cx('CBFormula-label')}></span>}
/>
</div>
);
}
}
export default themeable(Formula);

View File

@ -13,8 +13,8 @@ export interface ConditionFuncProps extends ThemeProps {
onChange: (value: ExpressionFunc) => void; onChange: (value: ExpressionFunc) => void;
fields?: Field[]; fields?: Field[];
funcs?: Funcs; funcs?: Funcs;
defaultType?: 'value' | 'field' | 'func' | 'raw'; defaultType?: 'value' | 'field' | 'func' | 'formula';
allowedTypes?: Array<'value' | 'field' | 'func' | 'raw'>; allowedTypes?: Array<'value' | 'field' | 'func' | 'formula'>;
} }
const option2value = (item: Func) => item.type; const option2value = (item: Func) => item.type;

View File

@ -99,6 +99,7 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
return ( return (
<Expression <Expression
config={config}
funcs={funcs} funcs={funcs}
value={value.left} value={value.left}
onChange={this.handleLeftChange} onChange={this.handleLeftChange}
@ -244,6 +245,7 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
return ( return (
<> <>
<Expression <Expression
config={config}
funcs={funcs} funcs={funcs}
valueField={field} valueField={field}
value={(value.right as Array<ExpressionComplex>)?.[0]} value={(value.right as Array<ExpressionComplex>)?.[0]}
@ -252,13 +254,14 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
defaultType="value" defaultType="value"
allowedTypes={ allowedTypes={
field?.valueTypes || field?.valueTypes ||
config.valueTypes || ['value', 'field', 'func', 'raw'] config.valueTypes || ['value', 'field', 'func', 'formula']
} }
/> />
<span className={cx('CBSeprator')}>~</span> <span className={cx('CBSeprator')}>~</span>
<Expression <Expression
config={config}
funcs={funcs} funcs={funcs}
valueField={field} valueField={field}
value={(value.right as Array<ExpressionComplex>)?.[1]} value={(value.right as Array<ExpressionComplex>)?.[1]}
@ -267,7 +270,7 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
defaultType="value" defaultType="value"
allowedTypes={ allowedTypes={
field?.valueTypes || field?.valueTypes ||
config.valueTypes || ['value', 'field', 'func', 'raw'] config.valueTypes || ['value', 'field', 'func', 'formula']
} }
/> />
</> </>
@ -276,6 +279,7 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
return ( return (
<Expression <Expression
config={config}
op={op} op={op}
funcs={funcs} funcs={funcs}
valueField={field} valueField={field}
@ -285,7 +289,7 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
defaultType="value" defaultType="value"
allowedTypes={ allowedTypes={
field?.valueTypes || field?.valueTypes ||
config.valueTypes || ['value', 'field', 'func', 'raw'] config.valueTypes || ['value', 'field', 'func', 'formula']
} }
/> />
); );

View File

@ -5,10 +5,14 @@ export interface BaseFieldConfig {
} }
export interface Config { export interface Config {
valueTypes?: Array<'value' | 'field' | 'func' | 'raw'>; valueTypes?: Array<'value' | 'field' | 'func' | 'formula'>;
fields?: Fields; fields?: Fields;
funcs?: Funcs; funcs?: Funcs;
maxLevel?: number; // 还没实现 maxLevel?: number; // 还没实现
// todo 起码需要支持 formula 组件可以自定义。
// todo 很多还不能配置。
types: { types: {
[propName: string]: Type; [propName: string]: Type;
}; };

View File

@ -4,7 +4,7 @@ import {LocaleProps, localeable} from '../../locale';
import {uncontrollable} from 'uncontrollable'; import {uncontrollable} from 'uncontrollable';
import {Fields, ConditionGroupValue, Funcs} from './types'; import {Fields, ConditionGroupValue, Funcs} from './types';
import ConditionGroup from './Group'; import ConditionGroup from './Group';
import defaultConfig from './config'; import defaultConfig, {Config} from './config';
import {autobind, findTreeIndex, spliceTree, getTree} from '../../utils/helper'; import {autobind, findTreeIndex, spliceTree, getTree} from '../../utils/helper';
import {findDOMNode} from 'react-dom'; import {findDOMNode} from 'react-dom';
import animtion from '../../utils/Animation'; import animtion from '../../utils/Animation';
@ -15,10 +15,11 @@ export interface ConditionBuilderProps extends ThemeProps, LocaleProps {
showNot?: boolean; showNot?: boolean;
value?: ConditionGroupValue; value?: ConditionGroupValue;
onChange: (value: ConditionGroupValue) => void; onChange: (value: ConditionGroupValue) => void;
config?: Config;
} }
export class QueryBuilder extends React.Component<ConditionBuilderProps> { export class QueryBuilder extends React.Component<ConditionBuilderProps> {
config = defaultConfig; config = {...defaultConfig, ...this.props.config};
dragTarget?: HTMLElement; dragTarget?: HTMLElement;
// dragNextSibling: Element | null; // dragNextSibling: Element | null;

View File

@ -48,8 +48,8 @@ export type ExpressionField = {
type: 'field'; type: 'field';
field: string; field: string;
}; };
export type ExpressionRaw = { export type ExpressionFormula = {
type: 'raw'; type: 'formula';
value: string; value: string;
}; };
@ -57,7 +57,7 @@ export type ExpressionComplex =
| ExpressionValue | ExpressionValue
| ExpressionFunc | ExpressionFunc
| ExpressionField | ExpressionField
| ExpressionRaw; | ExpressionFormula;
export interface ConditionRule { export interface ConditionRule {
id: any; id: any;
@ -78,7 +78,7 @@ export interface ConditionValue extends ConditionGroupValue {}
interface BaseField { interface BaseField {
type: FieldTypes; type: FieldTypes;
label: string; label: string;
valueTypes?: Array<'value' | 'field' | 'func' | 'raw'>; valueTypes?: Array<'value' | 'field' | 'func' | 'formula'>;
operators?: Array<string>; operators?: Array<string>;
// valueTypes 里面配置 func 才有效。 // valueTypes 里面配置 func 才有效。
@ -184,5 +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'>; valueTypes?: Array<'value' | 'field' | 'func' | 'formula'>;
}; };

View File

@ -483,7 +483,7 @@ export default class TextControl extends React.PureComponent<
(option: any) => !~selectedItem.indexOf(option.value) (option: any) => !~selectedItem.indexOf(option.value)
); );
if (creatable !== false && this.state.inputValue) { if (!filtedOptions.length && this.state.inputValue) {
filtedOptions.push({ filtedOptions.push({
[labelField || 'label']: this.state.inputValue, [labelField || 'label']: this.state.inputValue,
[valueField || 'value']: this.state.inputValue, [valueField || 'value']: this.state.inputValue,
@ -578,7 +578,7 @@ export default class TextControl extends React.PureComponent<
'is-disabled': option.disabled 'is-disabled': option.disabled
}) })
})} })}
key={option.value} key={`${option.label}-${option.value}`}
> >
{option.isNew ? ( {option.isNew ? (
<span> <span>