From 0f0f50358fd998bc015a54e836af2bdc741ae4a8 Mon Sep 17 00:00:00 2001 From: liaoxuezhi <2betop.cn@gmail.com> Date: Fri, 14 Aug 2020 00:13:40 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=8A=E6=88=90=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/components/Page/Form.jsx | 28 ++++- scss/components/_condition-builder.scss | 2 +- src/components/PopOverContainer.tsx | 96 +++++++++++++++ .../condition-builder/ConditionBuilder.tsx | 16 ++- .../condition-builder/ConditionGroup.tsx | 109 +++++++++++++++--- .../condition-builder/ConditionItem.tsx | 55 ++++++++- src/components/condition-builder/types.ts | 8 +- 7 files changed, 291 insertions(+), 23 deletions(-) create mode 100644 src/components/PopOverContainer.tsx diff --git a/examples/components/Page/Form.jsx b/examples/components/Page/Form.jsx index 81069dc8c..2e1041ff6 100644 --- a/examples/components/Page/Form.jsx +++ b/examples/components/Page/Form.jsx @@ -18,6 +18,23 @@ const fields = [ label: '入职时间', name: 'ruzhi', type: 'datetime' + }, + + { + label: '关系字段', + children: [ + { + label: '姓名', + name: 'name', + type: 'text' + }, + + { + label: '年龄', + name: 'age', + type: 'number' + } + ] } ]; @@ -43,7 +60,16 @@ export default { }, { - children: () => + name: 'a', + type: 'static', + tpl: '${a|json:2}' + }, + + { + name: 'a', + component: ({value, onChange}) => ( + + ) } ] } diff --git a/scss/components/_condition-builder.scss b/scss/components/_condition-builder.scss index bab436ce6..7faebb455 100644 --- a/scss/components/_condition-builder.scss +++ b/scss/components/_condition-builder.scss @@ -1,4 +1,4 @@ -.#{$ns}CBCGroup { +.#{$ns}CBGroup { &-toolbar { display: flex; flex-direction: row; diff --git a/src/components/PopOverContainer.tsx b/src/components/PopOverContainer.tsx new file mode 100644 index 000000000..e0540dc5c --- /dev/null +++ b/src/components/PopOverContainer.tsx @@ -0,0 +1,96 @@ +import React from 'react'; +import {autobind} from '../utils/helper'; +import Overlay from './Overlay'; +import PopOver from './PopOver'; +import {findDOMNode} from 'react-dom'; + +export interface PopOverContainerProps { + children: (props: { + onClick: (e: React.MouseEvent) => void; + isOpened: boolean; + ref: any; + }) => JSX.Element; + popOverRender: (props: {onClose: () => void}) => JSX.Element; + popOverContainer?: any; + popOverClassName?: string; +} + +export interface PopOverContainerState { + isOpened: boolean; +} + +export class PopOverContainer extends React.Component< + PopOverContainerProps, + PopOverContainerState +> { + state: PopOverContainerState = { + isOpened: false + }; + + target: any; + + @autobind + targetRef(target: any) { + this.target = target ? findDOMNode(target) : null; + } + + @autobind + handleClick() { + this.setState({ + isOpened: true + }); + } + + @autobind + close() { + this.setState({ + isOpened: false + }); + } + + @autobind + getTarget() { + return findDOMNode(this.target || this) as HTMLElement; + } + + @autobind + getParent() { + return this.getTarget()?.parentElement; + } + + render() { + const { + children, + popOverContainer, + popOverClassName, + popOverRender: dropdownRender + } = this.props; + return ( + <> + {children({ + isOpened: this.state.isOpened, + onClick: this.handleClick, + ref: this.targetRef + })} + + + + {dropdownRender({onClose: this.close})} + + + + ); + } +} + +export default PopOverContainer; diff --git a/src/components/condition-builder/ConditionBuilder.tsx b/src/components/condition-builder/ConditionBuilder.tsx index 5cd922275..9489db8a5 100644 --- a/src/components/condition-builder/ConditionBuilder.tsx +++ b/src/components/condition-builder/ConditionBuilder.tsx @@ -2,18 +2,28 @@ import React from 'react'; import {ThemeProps, themeable} from '../../theme'; import {LocaleProps, localeable} from '../../locale'; import {uncontrollable} from 'uncontrollable'; -import {FieldTypes, FieldItem, Fields} from './types'; +import {Fields, ConditionGroupValue} from './types'; import {ConditionGroup} from './ConditionGroup'; export interface QueryBuilderProps extends ThemeProps, LocaleProps { fields: Fields; + value?: ConditionGroupValue; + onChange: (value: ConditionGroupValue) => void; } export class QueryBuilder extends React.Component { render() { - const {classnames: cx, fields} = this.props; + const {classnames: cx, fields, onChange, value} = this.props; - return ; + return ( + + ); } } diff --git a/src/components/condition-builder/ConditionGroup.tsx b/src/components/condition-builder/ConditionGroup.tsx index 7822f997a..9f0e2fcb2 100644 --- a/src/components/condition-builder/ConditionGroup.tsx +++ b/src/components/condition-builder/ConditionGroup.tsx @@ -3,44 +3,127 @@ import {Fields, ConditionGroupValue} from './types'; import {ClassNamesFn} from '../../theme'; import Button from '../Button'; import {ConditionItem} from './ConditionItem'; -import {autobind} from '../../utils/helper'; +import {autobind, guid} from '../../utils/helper'; export interface ConditionGroupProps { value?: ConditionGroupValue; fields: Fields; onChange: (value: ConditionGroupValue) => void; classnames: ClassNamesFn; + removeable?: boolean; } export class ConditionGroup extends React.Component { + getValue() { + return { + conjunction: 'and' as 'and', + ...this.props.value + } as ConditionGroupValue; + } + @autobind - handleNotClick() {} + handleNotClick() { + const onChange = this.props.onChange; + let value = this.getValue(); + value.not = !value.not; + + onChange(value); + } + + @autobind + handleConjunctionClick() { + const onChange = this.props.onChange; + let value = this.getValue(); + value.conjunction = value.conjunction === 'and' ? 'or' : 'and'; + onChange(value); + } + + @autobind + handleAdd() { + const onChange = this.props.onChange; + let value = this.getValue(); + + value.children = Array.isArray(value.children) + ? value.children.concat() + : []; + + value.children.push({ + id: guid() + }); + onChange(value); + } + + @autobind + handleAddGroup() { + const onChange = this.props.onChange; + let value = this.getValue(); + + value.children = Array.isArray(value.children) + ? value.children.concat() + : []; + + value.children.push({ + id: guid(), + conjunction: 'and' + }); + onChange(value); + } render() { - const {classnames: cx, value, fields} = this.props; + const {classnames: cx, value, fields, onChange} = this.props; return ( -
-
-
+
+
+
- -
-
- - +
+ +
- {Array.isArray(value) - ? value.map(item => ) + {Array.isArray(value?.children) + ? value!.children.map(item => + (item as ConditionGroupValue).conjunction ? ( + + ) : ( + + ) + ) : null}
); diff --git a/src/components/condition-builder/ConditionItem.tsx b/src/components/condition-builder/ConditionItem.tsx index 52a82f704..eef8bf6f7 100644 --- a/src/components/condition-builder/ConditionItem.tsx +++ b/src/components/condition-builder/ConditionItem.tsx @@ -1,13 +1,64 @@ import React from 'react'; import {Fields, ConditionRule, ConditionGroupValue} from './types'; +import {ClassNamesFn} from '../../theme'; +import {Icon} from '../icons'; +import Select from '../Select'; +import {autobind} from '../../utils/helper'; +import PopOverContainer from '../PopOverContainer'; +import InputBox from '../InputBox'; +import ListRadios from '../ListRadios'; +import ResultBox from '../ResultBox'; export interface ConditionItemProps { fields: Fields; - value: ConditionRule | ConditionGroupValue; + value: ConditionRule; + classnames: ClassNamesFn; + onChange: (value: ConditionRule) => void; } export class ConditionItem extends React.Component { + @autobind + handleLeftSelect() {} + + renderLeft() { + const {value, fields} = this.props; + + return ( + ( + + )} + > + {({onClick, ref}) => ( + + )} + + ); + } + + renderItem() { + return null; + } + render() { - return

233

; + const {classnames: cx} = this.props; + + return ( +
+ + + + +
+ {this.renderLeft()} + {this.renderItem()} +
+
+ ); } } diff --git a/src/components/condition-builder/types.ts b/src/components/condition-builder/types.ts index c27b0b79e..86512b036 100644 --- a/src/components/condition-builder/types.ts +++ b/src/components/condition-builder/types.ts @@ -40,12 +40,14 @@ export type ConditionRightValue = }; export interface ConditionRule { - left: string; - op: OperatorType; - right: ConditionRightValue | Array; + id: any; + left?: string; + op?: OperatorType; + right?: ConditionRightValue | Array; } export interface ConditionGroupValue { + id: string; conjunction: 'and' | 'or'; not?: boolean; children?: Array;