Feat/tree cxd 4.0 (#3536)

* feat:tree ui级联同数据级联分离,行为对齐社区

* feat:云舍4.0样适配

* feat:先取消拖拽

* 问题修改

* chore:变量名修改

* 解决冲突 & 修改文档

* 修改文档

Co-authored-by: pianruijie <pianruijie@baidu.com>
This commit is contained in:
骈瑞杰 2022-04-14 19:18:20 +08:00 committed by GitHub
parent 2a29366403
commit 47c1c35058
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 191 additions and 93 deletions

View File

@ -159,7 +159,7 @@ order: 59
## 选中父节点是否自动选中子节点
默认选中父节点会自动选中子节点,可以设置`"cascade": true`,不自动选中子节点
`autoCheckChildren`默认为true选中父节点会自动选中子节点,可以设置`"autoCheckChildren": false`,不自动选中子节点
```schema: scope="body"
{
@ -209,6 +209,92 @@ order: 59
"name": "tree2",
"label": "不自动选中子节点",
"multiple": true,
"autoCheckChildren": false,
"options": [
{
"label": "A",
"value": "a"
},
{
"label": "B",
"value": "b",
"children": [
{
"label": "B-1",
"value": "b-1"
},
{
"label": "B-2",
"value": "b-2"
},
{
"label": "B-3",
"value": "b-3"
}
]
},
{
"label": "C",
"value": "c"
}
]
}
]
}
```
## 选中父节点自动选中子节点,数据是否包含父子节点的值
`cascade`默认为false子节点禁止反选值不包含子节点值配置`"cascade": true`,子节点可以反选,值包含父子节点值
```schema: scope="body"
{
"type": "form",
"debug": true,
"api": "/api/mock2/form/saveForm",
"body": [
{
"type": "input-tree",
"name": "tree1",
"label": "默认子节点禁止反选,值不包含子节点值",
"multiple": true,
"options": [
{
"label": "A",
"value": "a"
},
{
"label": "B",
"value": "b",
"children": [
{
"label": "B-1",
"value": "b-1"
},
{
"label": "B-2",
"value": "b-2"
},
{
"label": "B-3",
"value": "b-3"
}
]
},
{
"label": "C",
"value": "c"
}
]
},
{
"type": "divider"
},
{
"type": "input-tree",
"name": "tree2",
"label": "子节点可以反选,值包含父子节点值",
"multiple": true,
"cascade": true,
"options": [
{
@ -243,9 +329,7 @@ order: 59
}
```
## 选中父节点,值是否包含子节点
默认选中父节点,是不会带上子节点的值,想要自动带上子节点的值,那么配置`"withChildren": true`
`withChildren`默认为false子节点禁止反选值包含父子节点值配置`withChildren": true`,子节点禁止反选,值包含父子节点值
```schema: scope="body"
{
@ -256,7 +340,7 @@ order: 59
{
"type": "input-tree",
"name": "tree1",
"label": "默认不自动带上子节点的值",
"label": "默认不包含子节点的值",
"multiple": true,
"options": [
{
@ -340,7 +424,7 @@ order: 59
{
"type": "input-tree",
"name": "tree1",
"label": "默认不自动带上子节点的值",
"label": "默认不包含子节点的值",
"multiple": true,
"options": [
{
@ -825,9 +909,10 @@ true false true [{label: 'A/B/C', value: 'a/b/c'},{label: 'A
| showRadio | `boolean` | `false` | 是否显示单选按钮,`multiple` 为 `false` 是有效。 |
| initiallyOpen | `boolean` | `true` | 设置是否默认展开所有层级。 |
| unfoldedLevel | `number` | `0` | 设置默认展开的级数,只有`initiallyOpen`不是`true`时生效。 |
| cascade | `boolean` | `false` | 当选中父节点时不自动选择子节点。 |
| withChildren | `boolean` | `false` | 选中父节点时,值里面将包含子节点的值,否则只会保留父节点的值。 |
| onlyChildren | `boolean` | `false` | 多选时,选中父节点时,是否只将其子节点加入到值中。 |
| autoCheckChildren | `boolean` | `true` | 当选中父节点时级联选择子节点。 |
| cascade | `boolean` | `false` | autoCheckChildren为true时生效默认行为子节点禁用值只包含父节点值设置为true时子节点可反选值包含父子节点值。 |
| withChildren | `boolean` | `false` | cascade为false时生效选中父节点时值里面将包含父子节点的值否则只会保留父节点的值。
| onlyChildren | `boolean` | `false` | autoCheckChildren为true时生效不受cascade影响onlyChildren为trueui行为级联选中子节点子节点可反选值只包含子节点的值。 |
| rootCreatable | `boolean` | `false` | 是否可以创建顶级节点 |
| rootCreateTip | `string` | `"添加一级节点"` | 创建顶级节点的悬浮提示 |
| minLength | `number` | | 最少选中的节点数 |

View File

@ -1495,8 +1495,10 @@
--TabsTransfer-border-color: #e8e9eb;
--Tree-indent: var(--gap-md);
--Tree-icon-gap: var(--gap-xs);
--Tree-inputHeight: calc(var(--Form-input-height) * 0.85);
--Tree-item-onHover-bg: rgba(0, 126, 255, 0.08);
--Tree-item-onHover-bg-pure: rgba(0, 126, 255, 0.08);
--Tree-itemArrowWidth: #{px2rem(12px)};
--Tree-itemHeight: #{px2rem(30px)};
--Tree-itemLabel--onChecked-color: var(--Form-selectValue-color);

View File

@ -50,7 +50,7 @@
top: 2px;
width: px2rem(16px);
height: px2rem(16px);
margin-left: var(--gap-xs);
margin-left: var(--Tree-icon-gap);
}
}
}
@ -87,26 +87,35 @@
display: flex;
align-items: center;
position: relative;
&:hover {
background: var(--Tree-item-onHover-bg);
user-select: none;
margin-bottom: px2rem(4px);
padding-left: var(--Tree-icon-gap);
& > * {
position: relative;
z-index: 2;
}
> .#{$ns}Checkbox {
display: inline-flex;
align-self: center;
}
&:hover {
background: var(--Tree-item-onHover-bg-pure);
}
}
// & > * {
// position: relative;
// z-index: 2;
// }
// &:hover:after {
// position: absolute;
// content: '';
// z-index: 1;
// background: var(--Tree-item-onHover-bg);
// top: 0;
// right: 0;
// bottom: 0;
// left: -99999px;
// }
&-item {
.is-checked {
background: var(--Tree-item-onChekced-bg);
border-radius: var(--Tree-item-onChekced-bg-borderRadius);
}
.is-disabled {
color: var(--text--muted-color);
background: none;
&:hover {
background: none;
}
}
}
&.is-draggable &-itemLabel:hover::after {
@ -120,12 +129,12 @@
vertical-align: top;
height: var(--Tree-itemHeight);
line-height: var(--Tree-itemHeight);
padding-right: var(--gap-xs);
padding-right: var(--Tree-icon-gap);
> a {
display: inline-block;
vertical-align: middle;
margin-left: var(--gap-xs);
margin-left: var(--Tree-icon-gap);
cursor: pointer;
> svg {
@ -146,7 +155,7 @@
> a {
display: inline-block;
cursor: pointer;
margin-left: var(--gap-sm);
margin-left: var(--Tree-icon-gap);
color: var(--icon-color);
&:hover {
@ -205,7 +214,7 @@
width: $svgSize;
height: $svgSize;
top: $svgSize * 0.125;
margin-right: var(--gap-xs);
margin-right: var(--Tree-icon-gap);
}
}
@ -213,7 +222,7 @@
cursor: pointer;
width: var(--Tree-itemArrowWidth);
display: inline-flex;
margin-right: var(--gap-xs);
margin-right: var(--Tree-icon-gap);
// &:before {
// font-style: normal;
@ -236,7 +245,7 @@
&-itemArrowPlaceholder {
display: inline-block;
width: calc(var(--Tree-itemArrowWidth) + var(--gap-xs));
width: calc(var(--Tree-itemArrowWidth) + var(--Tree-icon-gap));
}
&-itemDrager {
@ -245,12 +254,12 @@
}
&-spinner {
margin-right: var(--gap-xs);
margin-right: var(--Tree-icon-gap);
}
&-itemIcon {
display: inline-flex;
margin-right: var(--gap-xs);
margin-right: var(--Tree-icon-gap);
}
&-rootIcon,
@ -262,30 +271,16 @@
height: px2rem(14px);
}
}
&-itemLabel {
user-select: none;
&.is-checked,
&.is-children-checked {
color: var(--Tree-itemLabel--onChecked-color);
}
&.is-disabled {
color: var(--text--muted-color);
}
> .#{$ns}Checkbox {
display: inline-flex;
align-self: center;
}
}
&-itemText {
cursor: pointer;
flex: 1 auto;
color: var(--Form-input-color);
line-height: var(--lineHeightBase);
padding: px2rem(4px) 0;
}
.is-disabled &-itemText {
color: var(--text--muted-color);
}
&-placeholder {
@ -313,7 +308,7 @@
&--hover {
border-radius: 0;
background-color: var(--Tree-item-onHover-bg);
background-color: var(--Tree-item-onHover-bg-pure);
&::after {
display: none;

View File

@ -632,12 +632,17 @@ $L1: 0px 4px 6px 0px rgba(8, 14, 26, 0.06),
--Satus-icon-width: #{px2rem(14px)};
--Tree-itemHeight: #{px2rem(32px)};
--Progress-borderRadius: #{$R7};
--Rating-inactive-color: #{$G9};
// tree
--Tree-item-onHover-bg-pure: #{$G10};
--Tree-item-onChekced-bg: var(--Form-select-menu-onHover-bg);
--Tree-item-onChekced-bg-borderRadius: #{px2rem(2px)};
--Tree-itemHeight: #{px2rem(24px)};
--Tree-icon-gap: var(--gap-sm);
// Formula
--InputFormula-code-bgColor: #{$G10};

View File

@ -88,14 +88,21 @@ interface TreeSelectorProps extends ThemeProps, LocaleProps {
pathSeparator?: string;
// 已选择节点路径
nodePath: any[];
// ui级联关系true代表级联选中false代表不级联默认为true
autoCheckChildren: boolean;
// 这个配置名字没取好目前的含义是如果这个配置成true点父级的时候子级点不会自选中。
// 否则点击父级,子节点选中。
/*
* autoCheckChildren为true时生效false
* 1.casacde为falseui行为为级联选中子节点
* 2.cascade为falsewithChildren为trueui行为为级联选中子节点
* 3.cascade为trueui行为级联选中子节点withChildren属性失效
* 4.cascade不论为true还是falseonlyChildren为trueui行为级联选中子节点
*/
cascade?: boolean;
selfDisabledAffectChildren?: boolean;
minLength?: number;
maxLength?: number;
// 是否为内建 增、改、删。当有复杂表单的时候直接抛出去让外层能统一处理
bultinCUD?: boolean;
rootCreatable?: boolean;
@ -157,6 +164,7 @@ export class TreeSelector extends React.Component<
hideRoot: true,
rootLabel: 'Tree.root',
rootValue: 0,
autoCheckChildren: true,
cascade: false,
selfDisabledAffectChildren: true,
rootCreateTip: 'Tree.addRoot',
@ -182,7 +190,6 @@ export class TreeSelector extends React.Component<
constructor(props: TreeSelectorProps) {
super(props);
this.state = {
value: value2array(
props.value,
@ -412,15 +419,12 @@ export class TreeSelector extends React.Component<
const props = this.props;
const value = this.state.value.concat();
const idx = value.indexOf(item);
const onlyChildren = props.onlyChildren;
const {onlyChildren, withChildren, cascade, autoCheckChildren} = props;
if (checked) {
~idx || value.push(item);
// cascade 为 true 表示父节点跟子节点没有级联关系。
if (!props.cascade) {
if (autoCheckChildren) {
const children = item.children ? item.children.concat([]) : [];
if (onlyChildren) {
// 父级选中的时候,子节点也都选中,但是自己不选中
!~idx && children.length && value.pop();
@ -445,7 +449,7 @@ export class TreeSelector extends React.Component<
value.splice(index, 1);
}
if (props.withChildren) {
if (withChildren || cascade) {
value.push(child);
}
@ -464,7 +468,7 @@ export class TreeSelector extends React.Component<
if (
parent.children.every((child: any) => ~value.indexOf(child))
) {
if (!props.withChildren) {
if (!cascade && !withChildren) {
parent.children.forEach((child: any) => {
const index = value.indexOf(child);
if (~index) {
@ -483,19 +487,18 @@ export class TreeSelector extends React.Component<
}
} else {
~idx && value.splice(idx, 1);
if (!props.cascade && (props.withChildren || onlyChildren)) {
const children = item.children ? item.children.concat([]) : [];
while (children.length) {
let child = children.shift();
let index = value.indexOf(child);
if (~index) {
value.splice(index, 1);
}
if (child.children && child.children.length) {
children.push.apply(children, child.children);
if (autoCheckChildren) {
if (cascade || withChildren || onlyChildren) {
const children = item.children ? item.children.concat([]) : [];
while (children.length) {
let child = children.shift();
let index = value.indexOf(child);
if (~index) {
value.splice(index, 1);
}
if (child.children && child.children.length) {
children.push.apply(children, child.children);
}
}
}
}
@ -664,7 +667,6 @@ export class TreeSelector extends React.Component<
@autobind
getDropInfo(e: React.DragEvent<Element>, node: Option): IDropInfo {
let rect = e.currentTarget.getBoundingClientRect();
const dragNode = this.dragNode;
const deltaX = Math.min(50, rect.width * 0.3);
const gap = node?.children?.length ? 0 : 16;
@ -676,7 +678,6 @@ export class TreeSelector extends React.Component<
let top = targetOffset.top - offset.top;
let {clientX, clientY} = e;
let position: IDropInfo['position'] =
clientY >= rect.top + rect.height / 2 ? 'bottom' : 'top';
let indicator;
@ -788,6 +789,7 @@ export class TreeSelector extends React.Component<
valueField,
iconField,
disabledField,
autoCheckChildren,
cascade,
selfDisabledAffectChildren,
onlyChildren,
@ -818,7 +820,6 @@ export class TreeSelector extends React.Component<
if (!isVisible(item as any, options)) {
return null;
}
const checked = !!~value.indexOf(item);
const selfDisabled = item[disabledField];
let selfChecked = !!uncheckable || checked;
@ -829,16 +830,15 @@ export class TreeSelector extends React.Component<
childrenItems = this.renderList(
item.children,
value,
cascade
? false
: uncheckable ||
(selfDisabledAffectChildren ? selfDisabled : false) ||
(multiple && checked)
(!autoCheckChildren || cascade)
? false: (uncheckable
|| (selfDisabledAffectChildren ? selfDisabled : false)
|| (multiple && checked))
);
selfChildrenChecked = !!childrenItems.childrenChecked;
if (
!selfChecked &&
onlyChildren &&
onlyChildren && autoCheckChildren &&
item.children.length === childrenItems.childrenChecked
) {
selfChecked = true;
@ -864,7 +864,7 @@ export class TreeSelector extends React.Component<
<Checkbox
size="sm"
disabled={nodeDisabled}
checked={selfChecked || (!cascade && selfChildrenChecked)}
checked={selfChecked || (autoCheckChildren && selfChildrenChecked)}
partial={!selfChecked}
onChange={this.handleCheck.bind(this, item, !selfChecked)}
/>

View File

@ -39,7 +39,16 @@ export interface TreeControlSchema extends FormOptionsControl {
showIcon?: boolean;
/**
*
* ui级联关系true代表级联选中false代表不级联true
*/
autoCheckChildren?: boolean;
/**
* autoCheckChildren为true时生效false
* 1.casacde为falseui行为为级联选中子节点
* 2.cascade为falsewithChildren为trueui行为为级联选中子节点
* 3.cascade为trueui行为级联选中子节点withChildren属性失效
* 4.cascade不论为true还是falseonlyChildren为trueui行为级联选中子节点
*/
cascade?: boolean;
@ -166,6 +175,7 @@ export default class TreeControl extends React.Component<TreeProps> {
loading,
hideRoot,
rootLabel,
autoCheckChildren,
cascade,
rootValue,
showIcon,
@ -222,6 +232,7 @@ export default class TreeControl extends React.Component<TreeProps> {
showIcon={showIcon}
showRadio={showRadio}
showOutline={showOutline}
autoCheckChildren={autoCheckChildren}
cascade={cascade}
foldedField="collapsed"
value={value || ''}