You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dashboard/src/components/search/Input.jsx

138 lines
4.7 KiB
JavaScript

import React from 'react';
import { Select } from 'antd';
import { fetchJSON } from './../../utils/request';
import { observer } from 'mobx-react';
import { isEmpty, merge, objectMapper } from './../../utils/commons';
const { Option } = Select;
let timeout;
let currentValue;
function curl(opts, callback) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
currentValue = opts.value;
function fake() {
if (currentValue === opts.value && opts.value === '空') {
const _p = [{ 'key': '0', 'label': '空' }];
return callback(_p);
}
const param = merge({ code: 'utf-8', q: String(opts.value).trim() }, opts.param);
// const str = new URLSearchParams({
// code: 'utf-8',
// q: opts.value,
// }).toString();
const resultkey = opts.resultkey || 'result';
fetchJSON(`${opts.url}`, param)
.then(d => {
if (currentValue === opts.value) {
const result = objectMapper(d[resultkey], opts.map) || [];
callback(result);
}
});
}
timeout = setTimeout(fake, 300);
}
/**
* 异步请求的下拉菜单, 可搜索
* @property {array} defaultOptions 默认选项 [{key: '', label: '' }]
* @property {string} url
* @property {object} map 异步结果的字段转换定义
* @property {boolean} autoGet 首次默认请求
* @property {string} resultkey 结果的根字段
*/
class SearchInput extends React.Component {
constructor(props) {
super(props);
this.state = {
data: this.props.defaultOptions || [],
value: undefined,
autoData: this.props.defaultOptions || [],
};
}
componentDidMount() {
if (this.props.autoGet === true) {
const { map, resultkey, dependenciesFun } = this.props;
const param = typeof dependenciesFun === 'function' ? dependenciesFun() : {};
const mapKey = Object.keys(map).reduce((r, v) => ({ ...r, [v]: typeof map[v] === 'string' ? { key: map[v] } : (map[v] || []).map(vi => ({ key: vi})) }), {});
curl({ value: '', url: this.props.url || '', map: mapKey, resultkey, param }, (data) =>
this.setState({ data, autoData: data }, () => (typeof this.props.onSearchAfter === 'function' ? this.props.onSearchAfter(data, this.state.value) : ''))
);
}
}
componentDidUpdate(prevProps) {
if (this.props.value !== prevProps.value) {
this.setState({ value: undefined });
}
}
handleClear = () => {
this.setState({ data: this.state.autoData });
};
handleSearch = value => {
if ( ! this.props.url && this.props.defaultOptions?.length) {
const f = this.props.defaultOptions.filter(r => String(r.label).indexOf(value) !== -1);
this.setState({ data: f || [] });
return false;
}
const { map, resultkey, dependenciesFun } = this.props;
const param = typeof dependenciesFun === 'function' ? dependenciesFun() : {};
// const mapKey = Object.keys(map).reduce((r, v) => ({ ...r, [v]: { key: map[v] } }), {});
const mapKey = Object.keys(map).reduce((r, v) => ({ ...r, [v]: typeof map[v] === 'string' ? { key: map[v] } : (map[v] || []).map(vi => ({ key: vi})) }), {});
if ((value && this.state.data.length === 0) || !isEmpty(param)) {
curl({ value, url: this.props.url || '', map: mapKey, resultkey, param }, (data) =>
this.setState({ data }, () => (typeof this.props.onSearchAfter === 'function' ? this.props.onSearchAfter(data, this.state.value) : ''))
);
} else {
this.setState({ data: this.state.autoData || [] });
}
};
handleChange = (value, option) => {
this.setState({ value }, () => this.props.onChange(value, option));
};
handleFilter = (value, option) => {
return String(option?.children || option?.label || option?.value || '').toLowerCase().includes(value.toLowerCase());
};
render() {
const options = this.state.data.map(d => <Option key={d.key} extradata={d.options}>{d.label}</Option>);
const { onSearchAfter, defaultOptions, autoGet, dependenciesFun, ...props } = this.props;
return (
<Select
{...props}
style={this.props.style || { width: '100%' }}
showSearch
labelInValue
value={this.state.value || this.props.value}
placeholder={this.props.placeholder}
defaultActiveFirstOption={false}
showArrow={false}
filterOption={this.handleFilter}
onSearch={this.handleSearch}
onChange={this.handleChange}
onFocus={() => this.handleSearch('')}
notFoundContent={null}
allowClear={true}
onClear={this.handleClear}
>
{options}
</Select>
);
}
}
export default observer(SearchInput);