forked from p96170835/amis
半成品
This commit is contained in:
parent
93297e8c5c
commit
24ce32cafa
|
@ -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: () => <ConditionBuilder fields={fields} />
|
||||
name: 'a',
|
||||
type: 'static',
|
||||
tpl: '${a|json:2}'
|
||||
},
|
||||
|
||||
{
|
||||
name: 'a',
|
||||
component: ({value, onChange}) => (
|
||||
<ConditionBuilder value={value} onChange={onChange} fields={fields} />
|
||||
)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.#{$ns}CBCGroup {
|
||||
.#{$ns}CBGroup {
|
||||
&-toolbar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
|
@ -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
|
||||
})}
|
||||
|
||||
<Overlay
|
||||
container={popOverContainer || this.getParent}
|
||||
target={this.getTarget}
|
||||
placement={'auto'}
|
||||
show={this.state.isOpened}
|
||||
>
|
||||
<PopOver
|
||||
overlay
|
||||
className={popOverClassName}
|
||||
style={{minWidth: this.target ? this.target.offsetWidth : 'auto'}}
|
||||
onHide={this.close}
|
||||
>
|
||||
{dropdownRender({onClose: this.close})}
|
||||
</PopOver>
|
||||
</Overlay>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PopOverContainer;
|
|
@ -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<QueryBuilderProps> {
|
||||
render() {
|
||||
const {classnames: cx, fields} = this.props;
|
||||
const {classnames: cx, fields, onChange, value} = this.props;
|
||||
|
||||
return <ConditionGroup fields={fields} value={undefined} classnames={cx} />;
|
||||
return (
|
||||
<ConditionGroup
|
||||
fields={fields}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
classnames={cx}
|
||||
removeable={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ConditionGroupProps> {
|
||||
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 (
|
||||
<div className={cx('CBCGroup')}>
|
||||
<div className={cx('CBCGroup-toolbar')}>
|
||||
<div className={cx('CBCGroup-toolbarLeft')}>
|
||||
<div className={cx('CBGroup')}>
|
||||
<div className={cx('CBGroup-toolbar')}>
|
||||
<div className={cx('CBGroup-toolbarLeft')}>
|
||||
<Button onClick={this.handleNotClick} size="sm" active={value?.not}>
|
||||
取反
|
||||
</Button>
|
||||
<Button size="sm" active={value?.conjunction !== 'or'}>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={this.handleConjunctionClick}
|
||||
active={value?.conjunction !== 'or'}
|
||||
>
|
||||
并且
|
||||
</Button>
|
||||
<Button size="sm" active={value?.conjunction === 'or'}>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={this.handleConjunctionClick}
|
||||
active={value?.conjunction === 'or'}
|
||||
>
|
||||
或者
|
||||
</Button>
|
||||
</div>
|
||||
<div className={cx('CBCGroup-toolbarRight')}>
|
||||
<Button size="sm">添加条件</Button>
|
||||
<Button size="sm">添加条件组</Button>
|
||||
<div className={cx('CBGroup-toolbarRight')}>
|
||||
<Button onClick={this.handleAdd} size="sm">
|
||||
添加条件
|
||||
</Button>
|
||||
<Button onClick={this.handleAddGroup} size="sm">
|
||||
添加条件组
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{Array.isArray(value)
|
||||
? value.map(item => <ConditionItem fields={fields} value={item} />)
|
||||
{Array.isArray(value?.children)
|
||||
? value!.children.map(item =>
|
||||
(item as ConditionGroupValue).conjunction ? (
|
||||
<ConditionGroup
|
||||
key={item.id}
|
||||
fields={fields}
|
||||
value={item as ConditionGroupValue}
|
||||
classnames={cx}
|
||||
onChange={onChange}
|
||||
/>
|
||||
) : (
|
||||
<ConditionItem
|
||||
key={item.id}
|
||||
fields={fields}
|
||||
value={item}
|
||||
classnames={cx}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)
|
||||
)
|
||||
: null}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -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<ConditionItemProps> {
|
||||
@autobind
|
||||
handleLeftSelect() {}
|
||||
|
||||
renderLeft() {
|
||||
const {value, fields} = this.props;
|
||||
|
||||
return (
|
||||
<PopOverContainer
|
||||
popOverRender={({onClose}) => (
|
||||
<ListRadios showRadio={false} options={fields} onChange={onClose} />
|
||||
)}
|
||||
>
|
||||
{({onClick, ref}) => (
|
||||
<ResultBox
|
||||
ref={ref}
|
||||
allowInput={false}
|
||||
onResultClick={onClick}
|
||||
placeholder="请选择"
|
||||
/>
|
||||
)}
|
||||
</PopOverContainer>
|
||||
);
|
||||
}
|
||||
|
||||
renderItem() {
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
return <p>233</p>;
|
||||
const {classnames: cx} = this.props;
|
||||
|
||||
return (
|
||||
<div className={cx('CBGroup-item')}>
|
||||
<a>
|
||||
<Icon icon="drag-bar" className="icon" />
|
||||
</a>
|
||||
|
||||
<div className={cx('CBGroup-itemBody')}>
|
||||
{this.renderLeft()}
|
||||
{this.renderItem()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,12 +40,14 @@ export type ConditionRightValue =
|
|||
};
|
||||
|
||||
export interface ConditionRule {
|
||||
left: string;
|
||||
op: OperatorType;
|
||||
right: ConditionRightValue | Array<ConditionRightValue>;
|
||||
id: any;
|
||||
left?: string;
|
||||
op?: OperatorType;
|
||||
right?: ConditionRightValue | Array<ConditionRightValue>;
|
||||
}
|
||||
|
||||
export interface ConditionGroupValue {
|
||||
id: string;
|
||||
conjunction: 'and' | 'or';
|
||||
not?: boolean;
|
||||
children?: Array<ConditionRule | ConditionGroupValue>;
|
||||
|
|
Loading…
Reference in New Issue