feat: transfer 树形搜索的时候支持高亮& feat: transfer 提供清空搜索的事件动作 & fix: transfer 穿梭器左上角的全选勾选时,没有处理 onlyChildren:true 的逻辑 (#7695)

* feat: transfer 树形搜索的时候支持高亮& feat: transfer 提供清空搜索的事件动作 & fix: transfer 穿梭器左上角的全选勾选时,没有处理 onlyChildren:true 的逻辑

* fix: transfer 穿梭器左上角的全选勾选时,没有处理 onlyChildren:true 的逻辑

* feat: transfer 树形搜索的时候支持高亮& feat: transfer 提供清空搜索的事件动作 & fix: transfer 穿梭器左上角的全选勾选时,没有处理 onlyChildren:true 的逻辑

* feat: transfer 树形搜索的时候支持高亮& feat: transfer 提供清空搜索的事件动作 & fix: transfer 穿梭器左上角的全选勾选时,没有处理 onlyChildren:true 的逻辑

* style: transfer文档动作完善
This commit is contained in:
sqzhou 2023-08-22 14:02:57 +08:00 committed by GitHub
parent 71bfc3f730
commit 866d3412b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 307 additions and 181 deletions

View File

@ -929,5 +929,6 @@ icon:
| --------- | -------------------------------------- | --------------------------------------------------------------------------------------- | | --------- | -------------------------------------- | --------------------------------------------------------------------------------------- |
| clear | - | 清空 | | clear | - | 清空 |
| reset | - | 将值重置为`resetValue`,若没有配置`resetValue`,则清空 | | reset | - | 将值重置为`resetValue`,若没有配置`resetValue`,则清空 |
| clearSearch | `left: boolean` 左侧搜索、`right:boolean`右侧搜索 | 默认清除所有搜索态,可以单独配置`left`、`right`为`true`来清空对应左侧或者右侧面板(`3.4.0`及以上版本支持) |
| selectAll | - | 全选 | | selectAll | - | 全选 |
| setValue | `value: string` \| `string[]` 更新的值 | 更新数据,开启`multiple`支持设置多项,开启`joinValues`时,多值用`,`分隔,否则多值用数组 | | setValue | `value: string` \| `string[]` 更新的值 | 更新数据,开启`multiple`支持设置多项,开启`joinValues`时,多值用`,`分隔,否则多值用数组 |

View File

@ -52,6 +52,29 @@ export default {
} }
} }
}, },
{
name: 'transferEvent2',
id: 'transferEvent2',
type: 'action',
label: '清空搜索',
level: 'primary',
className: 'mr-3 mb-3',
debugger: true,
onEvent: {
click: {
actions: [
{
actionType: 'clearSearch',
componentId: 'transfer-receiver',
args: {
left: true,
right: true
}
}
]
}
}
},
{ {
name: 'transferEvent2', name: 'transferEvent2',
id: 'transferEvent2', id: 'transferEvent2',
@ -84,6 +107,8 @@ export default {
id: 'transfer-receiver', id: 'transfer-receiver',
type: 'transfer', type: 'transfer',
name: 'transfer', name: 'transfer',
searchable: true,
resultSearchable: true,
debugger: true, debugger: true,
resetValue: 'c', resetValue: 'c',
source: '/api/mock2/form/getTreeOptions', source: '/api/mock2/form/getTreeOptions',

View File

@ -339,7 +339,8 @@ export interface ActionObject extends ButtonObject {
| 'collapse' | 'collapse'
| 'step-submit' | 'step-submit'
| 'selectAll' | 'selectAll'
| 'changeTabKey'; | 'changeTabKey'
| 'clearSearch';
api?: BaseApiObject | string; api?: BaseApiObject | string;
asyncApi?: BaseApiObject | string; asyncApi?: BaseApiObject | string;
payload?: any; payload?: any;

View File

@ -81,6 +81,7 @@ export class ResultList extends React.Component<
id = guid(); id = guid();
sortable?: Sortable; sortable?: Sortable;
unmounted = false; unmounted = false;
searchRef?: any;
componentDidMount() { componentDidMount() {
this.props.sortable && this.initSortable(); this.props.sortable && this.initSortable();
@ -99,6 +100,14 @@ export class ResultList extends React.Component<
this.unmounted = true; this.unmounted = true;
} }
@autobind
domSearchRef(ref: any) {
while (ref && ref.getWrappedInstance) {
ref = ref.getWrappedInstance();
}
this.searchRef = ref;
}
initSortable() { initSortable() {
const ns = this.props.classPrefix; const ns = this.props.classPrefix;
const dom = findDOMNode(this) as HTMLElement; const dom = findDOMNode(this) as HTMLElement;
@ -181,6 +190,14 @@ export class ResultList extends React.Component<
this.setState({searchResult: null}); this.setState({searchResult: null});
} }
@autobind
clearInput() {
if (this.props.searchable) {
this.searchRef?.clearInput?.();
}
this.clearSearch();
}
// 删除项 // 删除项
@autobind @autobind
handleCloseItem(e: React.MouseEvent<HTMLElement>, option: Option) { handleCloseItem(e: React.MouseEvent<HTMLElement>, option: Option) {
@ -359,6 +376,7 @@ export class ResultList extends React.Component<
{title ? <div className={cx('Selections-title')}>{title}</div> : null} {title ? <div className={cx('Selections-title')}>{title}</div> : null}
{searchable ? ( {searchable ? (
<TransferSearch <TransferSearch
ref={this.domSearchRef}
placeholder={searchPlaceholder} placeholder={searchPlaceholder}
onSearch={this.search} onSearch={this.search}
onCancelSearch={this.clearSearch} onCancelSearch={this.clearSearch}

View File

@ -68,6 +68,8 @@ export class BaseResultTableSelection extends BaseSelection<
searchTableOptions: [] searchTableOptions: []
}; };
searchRef?: any;
static getDerivedStateFromProps(props: ResultTableSelectionProps) { static getDerivedStateFromProps(props: ResultTableSelectionProps) {
const {options, value, option2value, valueField} = props; const {options, value, option2value, valueField} = props;
const valueArray = BaseSelection.value2array( const valueArray = BaseSelection.value2array(
@ -81,6 +83,14 @@ export class BaseResultTableSelection extends BaseSelection<
}; };
} }
@autobind
domSearchRef(ref: any) {
while (ref && ref.getWrappedInstance) {
ref = ref.getWrappedInstance();
}
this.searchRef = ref;
}
@autobind @autobind
handleCloseItem(option: Option) { handleCloseItem(option: Option) {
const {value, onChange, option2value, options, disabled, valueField} = const {value, onChange, option2value, options, disabled, valueField} =
@ -147,6 +157,14 @@ export class BaseResultTableSelection extends BaseSelection<
}); });
} }
@autobind
clearInput() {
if (this.props.searchable) {
this.searchRef?.clearInput?.();
}
this.clearSearch();
}
renderTable() { renderTable() {
const { const {
classnames: cx, classnames: cx,
@ -233,6 +251,7 @@ export class BaseResultTableSelection extends BaseSelection<
{title ? <div className={cx('Selections-title')}>{title}</div> : null} {title ? <div className={cx('Selections-title')}>{title}</div> : null}
{searchable ? ( {searchable ? (
<TransferSearch <TransferSearch
ref={this.domSearchRef}
placeholder={searchPlaceholder} placeholder={searchPlaceholder}
onSearch={this.search} onSearch={this.search}
onCancelSearch={this.clearSearch} onCancelSearch={this.clearSearch}

View File

@ -163,6 +163,8 @@ export class BaseResultTreeList extends React.Component<
searchTreeOptions: [] searchTreeOptions: []
}; };
searchRef?: any;
static getDerivedStateFromProps(props: ResultTreeListProps) { static getDerivedStateFromProps(props: ResultTreeListProps) {
const newOptions = getResultOptions( const newOptions = getResultOptions(
props.value, props.value,
@ -174,6 +176,14 @@ export class BaseResultTreeList extends React.Component<
}; };
} }
@autobind
domSearchRef(ref: any) {
while (ref && ref.getWrappedInstance) {
ref = ref.getWrappedInstance();
}
this.searchRef = ref;
}
// 删除非选中节点 // 删除非选中节点
@autobind @autobind
deleteTreeChecked(option: Option) { deleteTreeChecked(option: Option) {
@ -259,6 +269,14 @@ export class BaseResultTreeList extends React.Component<
}); });
} }
@autobind
clearInput() {
if (this.props.searchable) {
this.searchRef?.clearInput?.();
}
this.clearSearch();
}
renderTree() { renderTree() {
const { const {
className, className,
@ -314,6 +332,7 @@ export class BaseResultTreeList extends React.Component<
{title ? <div className={cx('Selections-title')}>{title}</div> : null} {title ? <div className={cx('Selections-title')}>{title}</div> : null}
{searchable ? ( {searchable ? (
<TransferSearch <TransferSearch
ref={this.domSearchRef}
placeholder={searchPlaceholder} placeholder={searchPlaceholder}
onSearch={this.search} onSearch={this.search}
onCancelSearch={this.clearSearch} onCancelSearch={this.clearSearch}

View File

@ -155,6 +155,7 @@ export class Transfer<
unmounted = false; unmounted = false;
cancelSearch?: () => void; cancelSearch?: () => void;
treeRef: any; treeRef: any;
resultRef: any;
componentDidMount() { componentDidMount() {
this.props?.onRef?.(this); this.props?.onRef?.(this);
@ -196,9 +197,20 @@ export class Transfer<
@autobind @autobind
domRef(ref: any) { domRef(ref: any) {
while (ref && ref.getWrappedInstance) {
ref = ref.getWrappedInstance();
}
this.treeRef = ref; this.treeRef = ref;
} }
@autobind
domResultRef(ref: any) {
while (ref && ref.getWrappedInstance) {
ref = ref.getWrappedInstance();
}
this.resultRef = ref;
}
@autobind @autobind
toggleAll() { toggleAll() {
const { const {
@ -207,7 +219,8 @@ export class Transfer<
onChange, onChange,
value, value,
onSelectAll, onSelectAll,
valueField = 'value' valueField = 'value',
selectMode
} = this.props; } = this.props;
let valueArray = BaseSelection.value2array( let valueArray = BaseSelection.value2array(
value, value,
@ -217,6 +230,11 @@ export class Transfer<
); );
const availableOptions = this.availableOptions; const availableOptions = this.availableOptions;
if (selectMode === 'tree') {
this.treeRef?.handleToggle();
return;
}
// availableOptions 中选项是否都被选中了 // availableOptions 中选项是否都被选中了
// to do intersectionWith 需要优化,大数据会卡死 // to do intersectionWith 需要优化,大数据会卡死
const isAvailableOptionsAllSelected = const isAvailableOptionsAllSelected =
@ -247,7 +265,17 @@ export class Transfer<
// 全选,给予动作全选使用 // 全选,给予动作全选使用
selectAll() { selectAll() {
const {options, option2value, onChange, valueField = 'value'} = this.props; const {
options,
option2value,
onChange,
valueField = 'value',
selectMode
} = this.props;
if (selectMode === 'tree') {
this.treeRef?.handleToggle(true);
return;
}
const availableOptions = flattenTree(options).filter( const availableOptions = flattenTree(options).filter(
(option, index, list) => (option, index, list) =>
!option.disabled && !option.disabled &&
@ -260,6 +288,20 @@ export class Transfer<
onChange?.(newValue); onChange?.(newValue);
} }
// 清空搜索
clearSearch(target?: {left?: boolean; right?: boolean}) {
if (!target) {
this.handleSeachCancel();
this.resultRef?.clearInput();
}
if (target?.left) {
this.handleSeachCancel();
}
if (target?.right) {
this.resultRef?.clearInput();
}
}
@autobind @autobind
clearAll() { clearAll() {
const {onChange} = this.props; const {onChange} = this.props;
@ -369,6 +411,22 @@ export class Transfer<
onChange && onChange(newArr); onChange && onChange(newArr);
} }
@autobind
optionItemRender(option: Option, states: ItemRenderStates) {
const {optionItemRender, labelField = 'label'} = this.props;
return optionItemRender
? optionItemRender(option, states)
: BaseSelection.itemRender(option, {labelField, ...states});
}
@autobind
resultItemRender(option: Option, states: ItemRenderStates) {
const {resultItemRender} = this.props;
return resultItemRender
? resultItemRender(option, states)
: ResultList.itemRender(option, states);
}
renderSelect( renderSelect(
props: TransferProps & { props: TransferProps & {
onToggleAll?: () => void; onToggleAll?: () => void;
@ -509,11 +567,15 @@ export class Transfer<
checkAllLabel, checkAllLabel,
onlyChildren onlyChildren
} = props; } = props;
const {isTreeDeferLoad, searchResult} = this.state; const {isTreeDeferLoad, searchResult, inputValue} = this.state;
const options = searchResult ?? []; const options = searchResult ?? [];
const mode = searchResultMode || selectMode; const mode = searchResultMode || selectMode;
const resultColumns = searchResultColumns || columns; const resultColumns = searchResultColumns || columns;
const treeItemRender =
!searchResult || optionItemRender ? this.optionItemRender : undefined;
const highlightTxt = searchResult ? inputValue : undefined;
return mode === 'table' ? ( return mode === 'table' ? (
<TableSelection <TableSelection
placeholder={noResultsText} placeholder={noResultsText}
@ -525,7 +587,7 @@ export class Transfer<
onChange={onChange} onChange={onChange}
option2value={option2value} option2value={option2value}
cellRender={cellRender} cellRender={cellRender}
itemRender={optionItemRender} itemRender={this.optionItemRender}
valueField={valueField} valueField={valueField}
multiple={multiple} multiple={multiple}
virtualThreshold={virtualThreshold} virtualThreshold={virtualThreshold}
@ -534,7 +596,7 @@ export class Transfer<
/> />
) : mode === 'tree' ? ( ) : mode === 'tree' ? (
<Tree <Tree
onRef={this.domRef} ref={this.domRef}
placeholder={noResultsText} placeholder={noResultsText}
className={cx('Transfer-selection')} className={cx('Transfer-selection')}
options={options} options={options}
@ -548,7 +610,8 @@ export class Transfer<
multiple={multiple} multiple={multiple}
cascade={true} cascade={true}
onlyChildren={onlyChildren ?? !isTreeDeferLoad} onlyChildren={onlyChildren ?? !isTreeDeferLoad}
itemRender={optionItemRender} highlightTxt={highlightTxt}
itemRender={treeItemRender}
labelField={labelField} labelField={labelField}
valueField={valueField} valueField={valueField}
virtualThreshold={virtualThreshold} virtualThreshold={virtualThreshold}
@ -565,7 +628,7 @@ export class Transfer<
disabled={disabled} disabled={disabled}
onChange={onChange} onChange={onChange}
option2value={option2value} option2value={option2value}
itemRender={optionItemRender} itemRender={this.optionItemRender}
multiple={multiple} multiple={multiple}
labelField={labelField} labelField={labelField}
valueField={valueField} valueField={valueField}
@ -584,7 +647,7 @@ export class Transfer<
disabled={disabled} disabled={disabled}
onChange={onChange} onChange={onChange}
option2value={option2value} option2value={option2value}
itemRender={optionItemRender} itemRender={this.optionItemRender}
multiple={multiple} multiple={multiple}
labelField={labelField} labelField={labelField}
valueField={valueField} valueField={valueField}
@ -647,7 +710,7 @@ export class Transfer<
/> />
) : selectMode === 'tree' ? ( ) : selectMode === 'tree' ? (
<Tree <Tree
onRef={this.domRef} ref={this.domRef}
placeholder={noResultsText} placeholder={noResultsText}
className={cx('Transfer-selection')} className={cx('Transfer-selection')}
options={options} options={options}
@ -745,7 +808,6 @@ export class Transfer<
cellRender, cellRender,
onChange, onChange,
value, value,
resultItemRender,
resultSearchable, resultSearchable,
resultSearchPlaceholder, resultSearchPlaceholder,
onResultSearch, onResultSearch,
@ -766,6 +828,7 @@ export class Transfer<
case 'table': case 'table':
return ( return (
<ResultTableList <ResultTableList
ref={this.domResultRef}
classnames={cx} classnames={cx}
columns={columns!} columns={columns!}
options={options || []} options={options || []}
@ -786,6 +849,7 @@ export class Transfer<
case 'tree': case 'tree':
return ( return (
<ResultTreeList <ResultTreeList
ref={this.domResultRef}
loadingConfig={loadingConfig} loadingConfig={loadingConfig}
classnames={cx} classnames={cx}
className={cx('Transfer-value')} className={cx('Transfer-value')}
@ -793,7 +857,7 @@ export class Transfer<
valueField={'value'} valueField={'value'}
value={value || []} value={value || []}
onChange={onChange!} onChange={onChange!}
itemRender={resultItemRender} itemRender={this.resultItemRender}
searchable={searchable} searchable={searchable}
placeholder={placeholder} placeholder={placeholder}
searchPlaceholder={resultSearchPlaceholder} searchPlaceholder={resultSearchPlaceholder}
@ -806,6 +870,7 @@ export class Transfer<
default: default:
return ( return (
<ResultList <ResultList
ref={this.domResultRef}
className={cx('Transfer-value')} className={cx('Transfer-value')}
sortable={sortable} sortable={sortable}
disabled={disabled} disabled={disabled}
@ -813,7 +878,7 @@ export class Transfer<
onChange={onChange} onChange={onChange}
placeholder={placeholder} placeholder={placeholder}
searchPlaceholder={resultSearchPlaceholder} searchPlaceholder={resultSearchPlaceholder}
itemRender={resultItemRender} itemRender={this.resultItemRender}
searchable={searchable} searchable={searchable}
onSearch={onResultSearch} onSearch={onResultSearch}
labelField={labelField} labelField={labelField}

View File

@ -84,6 +84,13 @@ export class TransferSearch extends React.Component<
}); });
} }
@autobind
clearInput() {
this.setState({
inputValue: ''
});
}
render() { render() {
const {classnames: cx, translate: __, placeholder, mobileUI} = this.props; const {classnames: cx, translate: __, placeholder, mobileUI} = this.props;

View File

@ -1355,6 +1355,19 @@ export class TreeSelector extends React.Component<
); );
} }
@autobind
handleToggle(bool?: boolean) {
const availableOptions = this.getAvailableOptions();
if (bool === undefined) {
const checkedAll = availableOptions.every(option =>
this.isItemChecked(option)
);
this.handleCheckAll(availableOptions, checkedAll);
return;
}
this.handleCheckAll(availableOptions, bool);
}
renderCheckAll() { renderCheckAll() {
const { const {
multiple, multiple,

View File

@ -1775,11 +1775,7 @@ exports[`Renderer:transfer follow left mode 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="法师" title="法师"
> >
<span 法师
class=""
>
法师
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -1815,11 +1811,7 @@ exports[`Renderer:transfer follow left mode 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="诸葛亮" title="诸葛亮"
> >
<span 诸葛亮
class=""
>
诸葛亮
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -1860,11 +1852,7 @@ exports[`Renderer:transfer follow left mode 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="战士" title="战士"
> >
<span 战士
class=""
>
战士
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -1900,11 +1888,7 @@ exports[`Renderer:transfer follow left mode 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="曹操" title="曹操"
> >
<span 曹操
class=""
>
曹操
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -1940,11 +1924,7 @@ exports[`Renderer:transfer follow left mode 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="钟无艳" title="钟无艳"
> >
<span 钟无艳
class=""
>
钟无艳
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -1985,11 +1965,7 @@ exports[`Renderer:transfer follow left mode 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="打野" title="打野"
> >
<span 打野
class=""
>
打野
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -2025,11 +2001,7 @@ exports[`Renderer:transfer follow left mode 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="李白" title="李白"
> >
<span 李白
class=""
>
李白
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -2065,11 +2037,7 @@ exports[`Renderer:transfer follow left mode 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="韩信" title="韩信"
> >
<span 韩信
class=""
>
韩信
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -2105,11 +2073,7 @@ exports[`Renderer:transfer follow left mode 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="云中君" title="云中君"
> >
<span 云中君
class=""
>
云中君
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -2443,11 +2407,7 @@ exports[`Renderer:transfer follow left mode 2`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="法师" title="法师"
> >
<span 法师
class=""
>
法师
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -2483,11 +2443,7 @@ exports[`Renderer:transfer follow left mode 2`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="诸葛亮" title="诸葛亮"
> >
<span 诸葛亮
class=""
>
诸葛亮
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -2528,11 +2484,7 @@ exports[`Renderer:transfer follow left mode 2`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="战士" title="战士"
> >
<span 战士
class=""
>
战士
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -2568,11 +2520,7 @@ exports[`Renderer:transfer follow left mode 2`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="曹操" title="曹操"
> >
<span 曹操
class=""
>
曹操
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -2608,11 +2556,7 @@ exports[`Renderer:transfer follow left mode 2`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="钟无艳" title="钟无艳"
> >
<span 钟无艳
class=""
>
钟无艳
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -2653,11 +2597,7 @@ exports[`Renderer:transfer follow left mode 2`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="打野" title="打野"
> >
<span 打野
class=""
>
打野
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -2693,11 +2633,7 @@ exports[`Renderer:transfer follow left mode 2`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="李白" title="李白"
> >
<span 李白
class=""
>
李白
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -2733,11 +2669,7 @@ exports[`Renderer:transfer follow left mode 2`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="韩信" title="韩信"
> >
<span 韩信
class=""
>
韩信
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -2773,11 +2705,7 @@ exports[`Renderer:transfer follow left mode 2`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="云中君" title="云中君"
> >
<span 云中君
class=""
>
云中君
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -5897,11 +5825,7 @@ exports[`Renderer:transfer tree 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="法师" title="法师"
> >
<span 法师
class=""
>
法师
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -5937,11 +5861,7 @@ exports[`Renderer:transfer tree 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="诸葛亮" title="诸葛亮"
> >
<span 诸葛亮
class=""
>
诸葛亮
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -5982,11 +5902,7 @@ exports[`Renderer:transfer tree 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="战士" title="战士"
> >
<span 战士
class=""
>
战士
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -6022,11 +5938,7 @@ exports[`Renderer:transfer tree 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="曹操" title="曹操"
> >
<span 曹操
class=""
>
曹操
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -6062,11 +5974,7 @@ exports[`Renderer:transfer tree 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="钟无艳" title="钟无艳"
> >
<span 钟无艳
class=""
>
钟无艳
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -6107,11 +6015,7 @@ exports[`Renderer:transfer tree 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="打野" title="打野"
> >
<span 打野
class=""
>
打野
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -6147,11 +6051,7 @@ exports[`Renderer:transfer tree 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="李白" title="李白"
> >
<span 李白
class=""
>
李白
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -6187,11 +6087,7 @@ exports[`Renderer:transfer tree 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="韩信" title="韩信"
> >
<span 韩信
class=""
>
韩信
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -6227,11 +6123,7 @@ exports[`Renderer:transfer tree 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="云中君" title="云中君"
> >
<span 云中君
class=""
>
云中君
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -6431,11 +6323,7 @@ exports[`Renderer:transfer with showInvalidMatch & unmatched do not add 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="诸葛亮" title="诸葛亮"
> >
<span 诸葛亮
class=""
>
诸葛亮
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -6471,11 +6359,7 @@ exports[`Renderer:transfer with showInvalidMatch & unmatched do not add 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="曹操" title="曹操"
> >
<span 曹操
class=""
>
曹操
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"
@ -6511,11 +6395,7 @@ exports[`Renderer:transfer with showInvalidMatch & unmatched do not add 1`] = `
class="cxd-Tree-itemText" class="cxd-Tree-itemText"
title="钟无艳" title="钟无艳"
> >
<span 钟无艳
class=""
>
钟无艳
</span>
</span> </span>
<div <div
class="cxd-Tree-item-icons" class="cxd-Tree-item-icons"

View File

@ -1229,4 +1229,85 @@ test('Renderer:transfer with searchApi', async () => {
const caocao = container.querySelector('span[title=曹操]'); const caocao = container.querySelector('span[title=曹操]');
expect(caocao).toBeNull(); expect(caocao).toBeNull();
});
test('Renderer:transfer tree onlyChildren true', async () => {
const onSubmit = jest.fn();
const schema = {
"type": "form",
"api": "/api/mock2/form/saveForm",
"debug": true,
"body": [
{
"label": "默认",
"type": "transfer",
"name": "transfer",
"value": "libai",
"selectMode": "tree",
"searchable": true,
"onlyChildren": true,
"options": [
{
"label": "法师",
"children": [
{
"label": "诸葛亮",
"value": "zhugeliang"
}
]
},
{
"label": "战士",
"value": "战士",
"children": [
{
"label": "曹操",
"disabled": true,
"value": "caocao"
},
{
"label": "钟无艳",
"value": "zhongwuyan"
}
]
},
{
"label": "打野",
"children": [
{
"label": "李白",
"value": "libai"
},
{
"label": "韩信",
"value": "hanxin"
},
{
"label": "云中君",
"value": "yunzhongjun"
}
]
}
]
}
]
};
const {getByText, container} = render(
amisRender(schema, {onSubmit}, makeEnv({}))
);
const checkbox = container.querySelector('.cxd-Checkbox');
expect(checkbox).not.toBeNull();
checkbox && fireEvent.click(checkbox);
fireEvent.click(getByText('提交'));
await wait(100);
expect(onSubmit).toBeCalledTimes(1);
expect(onSubmit.mock.calls[0][0]).toEqual({
transfer: "zhugeliang,zhongwuyan,libai,hanxin,yunzhongjun"
});
}); });

View File

@ -428,29 +428,21 @@ export class BaseTransferRenderer<
@autobind @autobind
optionItemRender(option: Option, states: ItemRenderStates) { optionItemRender(option: Option, states: ItemRenderStates) {
const {menuTpl, render, data, labelField = 'label'} = this.props; const {menuTpl, render, data} = this.props;
if (menuTpl) { return render(`item/${states.index}`, menuTpl, {
return render(`item/${states.index}`, menuTpl, { data: createObject(createObject(data, states), option)
data: createObject(createObject(data, states), option) });
});
}
return BaseSelection.itemRender(option, {labelField, ...states});
} }
@autobind @autobind
resultItemRender(option: Option, states: ItemRenderStates) { resultItemRender(option: Option, states: ItemRenderStates) {
const {valueTpl, render, data} = this.props; const {valueTpl, render, data} = this.props;
if (valueTpl) { return render(`value/${states.index}`, valueTpl, {
return render(`value/${states.index}`, valueTpl, { onChange: states.onChange,
onChange: states.onChange, data: createObject(createObject(data, states), option)
data: createObject(createObject(data, states), option) });
});
}
return ResultList.itemRender(option, states);
} }
@autobind @autobind
@ -508,6 +500,10 @@ export class BaseTransferRenderer<
case 'selectAll': case 'selectAll':
this.tranferRef?.selectAll(); this.tranferRef?.selectAll();
break; break;
case 'clearSearch': {
this.tranferRef?.clearSearch(data);
break;
}
} }
} }
@ -533,6 +529,7 @@ export class BaseTransferRenderer<
selectTitle, selectTitle,
resultTitle, resultTitle,
menuTpl, menuTpl,
valueTpl,
searchPlaceholder, searchPlaceholder,
resultListModeFollowSelect = false, resultListModeFollowSelect = false,
resultSearchPlaceholder, resultSearchPlaceholder,
@ -597,8 +594,8 @@ export class BaseTransferRenderer<
statistics={statistics} statistics={statistics}
labelField={labelField} labelField={labelField}
valueField={valueField} valueField={valueField}
optionItemRender={this.optionItemRender} optionItemRender={menuTpl ? this.optionItemRender : undefined}
resultItemRender={this.resultItemRender} resultItemRender={valueTpl ? this.resultItemRender : undefined}
onSelectAll={this.onSelectAll} onSelectAll={this.onSelectAll}
onRef={this.getRef} onRef={this.getRef}
virtualThreshold={virtualThreshold} virtualThreshold={virtualThreshold}