mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-30 02:58:05 +08:00
补充搜索功能
This commit is contained in:
parent
1442357975
commit
2f22d7621b
@ -72,3 +72,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}TransferControl {
|
||||
position: relative;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ export interface TransferPorps extends ThemeProps, CheckboxesProps {
|
||||
onSearch?: (
|
||||
term: string,
|
||||
setCancel: (cancel: () => void) => void
|
||||
) => Promise<Options>;
|
||||
) => Promise<Options | void>;
|
||||
|
||||
// 自定义选择框相关
|
||||
selectRender?: (props: TransferPorps) => JSX.Element;
|
||||
@ -216,6 +216,7 @@ export class Transfer extends React.Component<TransferPorps, TransferState> {
|
||||
renderSearchResult() {
|
||||
const {
|
||||
searchResultMode,
|
||||
selectMode,
|
||||
noResultsText,
|
||||
searchResultColumns,
|
||||
classnames: cx,
|
||||
@ -224,8 +225,9 @@ export class Transfer extends React.Component<TransferPorps, TransferState> {
|
||||
option2value
|
||||
} = this.props;
|
||||
const options = this.state.searchResult || [];
|
||||
const mode = searchResultMode || selectMode;
|
||||
|
||||
return searchResultMode === 'table' ? (
|
||||
return mode === 'table' ? (
|
||||
<TableCheckboxes
|
||||
placeholder={noResultsText}
|
||||
className={cx('Transfer-checkboxes')}
|
||||
@ -235,7 +237,7 @@ export class Transfer extends React.Component<TransferPorps, TransferState> {
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
/>
|
||||
) : searchResultMode === 'tree' ? (
|
||||
) : mode === 'tree' ? (
|
||||
<TreeCheckboxes
|
||||
placeholder={noResultsText}
|
||||
className={cx('Transfer-checkboxes')}
|
||||
|
@ -45,7 +45,7 @@ export interface FormItemProps extends RendererProps {
|
||||
formHorizontal: FormHorizontal;
|
||||
defaultSize?: 'xs' | 'sm' | 'md' | 'lg' | 'full';
|
||||
size?: 'xs' | 'sm' | 'md' | 'lg' | 'full';
|
||||
disabled: boolean;
|
||||
disabled?: boolean;
|
||||
btnDisabled: boolean;
|
||||
defaultValue: any;
|
||||
value: any;
|
||||
|
@ -6,7 +6,13 @@ import Checkbox from '../../components/Checkbox';
|
||||
import PopOver from '../../components/PopOver';
|
||||
import {RootCloseWrapper} from 'react-overlays';
|
||||
import {Icon} from '../../components/icons';
|
||||
import {autobind, flattenTree, isEmpty, filterTree} from '../../utils/helper';
|
||||
import {
|
||||
autobind,
|
||||
flattenTree,
|
||||
isEmpty,
|
||||
filterTree,
|
||||
string2regExp
|
||||
} from '../../utils/helper';
|
||||
import {dataMapping} from '../../utils/tpl-builtin';
|
||||
import {OptionsControl, OptionsControlProps} from '../Form/Options';
|
||||
import {Option, Options} from '../../components/Select';
|
||||
@ -357,7 +363,7 @@ export default class NestedSelectControl extends React.Component<
|
||||
const inputValue = evt.currentTarget.value;
|
||||
const {options, labelField, valueField} = this.props;
|
||||
|
||||
const regexp = new RegExp(`${inputValue}`, 'i');
|
||||
const regexp = string2regExp(inputValue);
|
||||
|
||||
let filtedOptions =
|
||||
inputValue && this.state.isOpened
|
||||
|
@ -2,13 +2,22 @@ import {OptionsControlProps, OptionsControl} from './Options';
|
||||
import React from 'react';
|
||||
import Transfer from '../../components/Transfer';
|
||||
import {Option} from './Options';
|
||||
import {autobind} from '../../utils/helper';
|
||||
import {
|
||||
autobind,
|
||||
filterTree,
|
||||
string2regExp,
|
||||
createObject
|
||||
} from '../../utils/helper';
|
||||
import {Api} from '../../types';
|
||||
import Spinner from '../../components/Spinner';
|
||||
import find from 'lodash/find';
|
||||
import {optionValueCompare} from '../../components/Select';
|
||||
|
||||
export interface TransferProps extends OptionsControlProps {
|
||||
sortable?: boolean;
|
||||
selectMode?: 'table' | 'list' | 'tree';
|
||||
columns?: Array<any>;
|
||||
searchable?: boolean;
|
||||
searchApi?: Api; // todo 通过传递进去 onSearch 实现。
|
||||
}
|
||||
|
||||
@ -23,20 +32,38 @@ export class TransferRenderer extends React.Component<TransferProps> {
|
||||
joinValues,
|
||||
delimiter,
|
||||
valueField,
|
||||
extractValue
|
||||
extractValue,
|
||||
options,
|
||||
setOptions
|
||||
} = this.props;
|
||||
let newValue: any = value;
|
||||
let newOptions = options.concat();
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
if (joinValues || extractValue) {
|
||||
newValue = value.map(item => {
|
||||
const resolved = find(
|
||||
options,
|
||||
optionValueCompare(
|
||||
item[valueField || 'value'],
|
||||
valueField || 'value'
|
||||
)
|
||||
);
|
||||
|
||||
if (!resolved) {
|
||||
newOptions.push(item);
|
||||
}
|
||||
|
||||
return item[valueField || 'value'];
|
||||
});
|
||||
}
|
||||
|
||||
if (joinValues) {
|
||||
newValue = value
|
||||
.map(item => item[valueField || 'value'])
|
||||
.join(delimiter || ',');
|
||||
} else if (extractValue) {
|
||||
newValue = value.map(item => item[valueField || 'value']);
|
||||
newValue = newValue.join(delimiter || ',');
|
||||
}
|
||||
}
|
||||
|
||||
newOptions.length > options.length && setOptions(newOptions);
|
||||
onChange(newValue);
|
||||
}
|
||||
|
||||
@ -45,6 +72,56 @@ export class TransferRenderer extends React.Component<TransferProps> {
|
||||
return option;
|
||||
}
|
||||
|
||||
@autobind
|
||||
async handleSearch(term: string) {
|
||||
const {searchApi, options, labelField, valueField, env, data} = this.props;
|
||||
|
||||
if (searchApi) {
|
||||
const payload = await env.fetcher(searchApi, createObject(data, {term}));
|
||||
|
||||
if (!payload.ok) {
|
||||
env.notify('error', payload.msg || '搜索请求异常');
|
||||
return [];
|
||||
}
|
||||
|
||||
const result = payload.data.options || payload.data.items || payload.data;
|
||||
if (!Array.isArray(result)) {
|
||||
env.notify('error', '期望接口返回数组信息');
|
||||
return [];
|
||||
}
|
||||
|
||||
return result.map(item => {
|
||||
let resolved: any = null;
|
||||
|
||||
if (Array.isArray(options)) {
|
||||
resolved = find(
|
||||
options,
|
||||
optionValueCompare(item[valueField || 'value'], valueField)
|
||||
);
|
||||
}
|
||||
|
||||
return resolved || item;
|
||||
});
|
||||
} else if (term) {
|
||||
const regexp = string2regExp(term);
|
||||
|
||||
return filterTree(
|
||||
options,
|
||||
(option: Option) => {
|
||||
return !!(
|
||||
(Array.isArray(option.children) && option.children.length) ||
|
||||
regexp.test(option[labelField || 'label']) ||
|
||||
regexp.test(option[valueField || 'value'])
|
||||
);
|
||||
},
|
||||
0,
|
||||
true
|
||||
);
|
||||
} else {
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
classnames: cx,
|
||||
@ -52,7 +129,10 @@ export class TransferRenderer extends React.Component<TransferProps> {
|
||||
selectedOptions,
|
||||
sortable,
|
||||
selectMode,
|
||||
columns
|
||||
columns,
|
||||
loading,
|
||||
searchable,
|
||||
searchApi
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -65,7 +145,10 @@ export class TransferRenderer extends React.Component<TransferProps> {
|
||||
sortable={sortable}
|
||||
selectMode={selectMode}
|
||||
columns={columns}
|
||||
onSearch={searchable ? this.handleSearch : undefined}
|
||||
/>
|
||||
|
||||
<Spinner overlay key="info" show={loading} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -251,9 +251,10 @@ export function anyChanged(
|
||||
to: {[propName: string]: any},
|
||||
strictMode: boolean = true
|
||||
): boolean {
|
||||
return (typeof attrs === 'string' ? attrs.split(/\s*,\s*/) : attrs).some(
|
||||
key => (strictMode ? from[key] !== to[key] : from[key] != to[key])
|
||||
);
|
||||
return (typeof attrs === 'string'
|
||||
? attrs.split(/\s*,\s*/)
|
||||
: attrs
|
||||
).some(key => (strictMode ? from[key] !== to[key] : from[key] != to[key]));
|
||||
}
|
||||
|
||||
export function rmUndefined(obj: PlainObject) {
|
||||
@ -362,7 +363,7 @@ export function makeColumnClassBuild(
|
||||
let count = 12;
|
||||
let step = Math.floor(count / steps);
|
||||
|
||||
return function(schema: Schema) {
|
||||
return function (schema: Schema) {
|
||||
if (
|
||||
schema.columnClassName &&
|
||||
/\bcol-(?:xs|sm|md|lg)-(\d+)\b/.test(schema.columnClassName)
|
||||
@ -470,7 +471,7 @@ export function promisify<T extends Function>(
|
||||
) => Promise<any> & {
|
||||
raw: T;
|
||||
} {
|
||||
let promisified = function() {
|
||||
let promisified = function () {
|
||||
try {
|
||||
const ret = fn.apply(null, arguments);
|
||||
if (ret && ret.then) {
|
||||
@ -1029,6 +1030,17 @@ export function getLevelFromClassName(
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
export function string2regExp(value: string, caseSensitive = false) {
|
||||
if (typeof value !== 'string') {
|
||||
throw new TypeError('Expected a string');
|
||||
}
|
||||
|
||||
return new RegExp(
|
||||
value.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d'),
|
||||
!caseSensitive ? 'i' : ''
|
||||
);
|
||||
}
|
||||
|
||||
export function pickEventsProps(props: any) {
|
||||
const ret: any = {};
|
||||
props &&
|
||||
@ -1040,7 +1052,7 @@ export function pickEventsProps(props: any) {
|
||||
|
||||
export const autobind = boundMethod;
|
||||
|
||||
export const bulkBindFunctions = function<
|
||||
export const bulkBindFunctions = function <
|
||||
T extends {
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user