UNPKG

hc-components-test

Version:

基于react的通用组件库

429 lines (408 loc) 11.8 kB
import React, {Component} from 'react'; import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import Select from 'antd/lib/select'; import Pagination from 'antd/lib/pagination'; import Icon from 'antd/lib/icon'; import './index.less'; export class Search extends React.PureComponent { static propTypes = { value: PropTypes.any, selectedItem: PropTypes.object, options: PropTypes.array, select: PropTypes.object, multiple: PropTypes.bool, rowKey: PropTypes.string.isRequired, labelKey: PropTypes.string.isRequired, disabled: PropTypes.bool, onChange: PropTypes.func.isRequired } static contextTypes = { dataModel: PropTypes.object.isRequired } static defaultProps = { options: [], multiple: false, keyword: '', select: { showSearch: true, allowClear: true }, params: {}, rowKey: 'id', labelKey: 'name', onChange: () => {}, onRendered: () => {} } constructor(props, context) { super(props, context); let value; if (props.multiple) { value = props.value || []; } else { value = props.value || ''; } // value是真实的值,keyword是搜索词,value优先级高,否则才有keyword this.state = { current: 1, value: value, multiMap: {}, list: props.options, keyword: props.keyword, disabled: props.disabled, total: 0, loading: true } if (!props.multiple && props.selectedItem) { this.state.keyword = ''; this.select(props.selectedItem, true); } else if (props.options.length){ this.props.onRendered(); }else if(!props.disabled) { if (props.multiple) { if (value) { this.getData({page: 1, ids: value, value: value, keyword: '', ids: ''}, this.props.onRendered); } else { this.getData({page: 1, keyword: props.keyword, ids: ''}, this.props.onRendered); } } else { if (value) { this.getItem({id: value}); } else { this.getData({page: 1, keyword: '', ids: ''}, this.props.onRendered); } } } } toSelect(item, flag) { if (item[this.props.rowKey]) { if (item[this.props.labelKey]) { // value 和 keyword只能二选一 if (flag) { Object.assign(this.state, { value: item[this.props.rowKey] + '', list: [item] }); } else { this.setState({ value: item[this.props.rowKey] + '', list: [item] }); } } else { this.getItem({ id: item[this.props.rowKey] }); } } } select(item, flag) { if (item instanceof Promise) { item.then(this.toSelect.bind(this)); } else { this.toSelect(item, flag); } } componentWillReceiveProps(nextProps) { let enabled = false; if (this.props.disabled) { if (!nextProps.disabled) { enabled = true; } } else if (!nextProps.disabled) { enabled = true; } if (enabled) { const hasValue = this.props.multiple ? this.props.value && this.props.value.length : this.props.value; if (nextProps.value && !hasValue) { // 此时value必须输入selectedItem if (nextProps.multiple) { this.getData({page: 1, value: nextProps.value, ids: nextProps.value, keyword: ''}, this.props.onRendered); } else { if (nextProps.selectedItem) { if (nextProps.selectedItem[this.props.rowKey] != nextProps.value) { this.select(nextProps.selectedItem) } } else if (nextProps.noSearch) { if (nextProps.options.length) { const value = params.value || (this.props.multiple ? [] : ''); this.setState({list: nextProps.options, value: value, keyword: '', total: 0, loading: false}); this.props.onRendered(); } else { this.getData({page: 1, keyword: '', value: nextProps.value, ids: ''}, this.props.onRendered); } } else { if (nextProps.value != this.state.value) { this.getItem({id: nextProps.value}); } } } } else if (nextProps.keyword != this.props.keyword) { this.getData({page: 1, keyword: nextProps.keyword, ids: ''}, this.props.onRendered); } else if (this.props.disabled) { this.getData({page: 1, keyword: '', ids: ''}, this.props.onRendered); } } } getItem(params) { this.setState({keyword: ''}); const dataModel = this.context.dataModel; if (dataModel && dataModel.getItem) { const _params = Object.assign(this.props.params, params); const promise = dataModel.getItem(_params); promise.then(data => { if (this.state.keyword) { return; } this.setState({ list: [data], value: params.id + '', total: 0, loading: false }); }); return promise; } else { this.setState({ value: params.id + '', total: 0, loading: false }); } } getData(params, callback) { this.setState({loading: true}); const dataModel = this.context.dataModel; const rowKey = this.props.rowKey; if (dataModel) { const keyword = params.keyword; const _params = Object.assign(this.props.params, params); if (keyword) { _params.keyword = encodeURIComponent(keyword) } const promise = dataModel.getData(_params); promise.then(data => { const hasValue = this.props.multiple ? this.state.value.length : this.state.value; if (!params.ids && (hasValue || params.keyword !== this.state.keyword)) { this.setState({loading: false}); return; } const value = params.value || (this.props.multiple ? [] : ''); const newState = { value: value, keyword: params.keyword, total: 0, loading: false }; if (this.props.noSearch) { newState.list = data; } else { if (data.list.length == data.total) { newState.list = data.list; } else { newState.list = data.list; newState.total = data.total; newState.current = params.page; } } if (this.props.multiple) { let multiMap = {}; if (params.ids) { newState .list .forEach(item => { if (params.ids.indexOf(item[rowKey]) > -1) { multiMap[item[rowKey]] = item; } }) newState.multiMap = multiMap; } else if (this.state.value.length) { newState.list = newState .list .filter(item => { if (this.state.multiMap[item[rowKey]]) { return false; } else { return true; } }); for (let key in this.state.multiMap) { newState .list .unshift(this.state.multiMap[key]); } } } this.setState(newState); callback && callback(); return newState.list; }); return promise; } } handleSearch(params, callback) { if (this.props.noSearch) { return; } callback = callback || function () {}; clearTimeout(this.$timer_); this.$timer_ = setTimeout(() => { const value = this.props.multiple ? this.state.value : ''; this.setState({ keyword: params.keyword, current: params.page || 1, value: value }); if (!this.props.multiple && this.state.value) { this .props .onChange(value); } const promise = this.getData(params); promise && promise.then(res => callback(null, res), err => callback(err)); }, 200); } render() { const { rowKey, labelKey, onChange, noSearch, select, multiple, disabled } = this.props; const { value, keyword, current, loading, total, list } = this.state; const selectProps = Object.assign(select, { disabled: disabled, multiple: multiple, value: value || keyword || undefined }); if(!noSearch && total && !list.pager){ list.pager = true; list.push({ [rowKey]: 'miniPager', [labelKey]: ( <Pagination size="small" current={current} total={total} showLessItems={true} onChange={(page) => { this.handleSearch({page: page, keyword: keyword}) }} showTotal={() => loading ? (<Icon type="loading"/>) : `共匹配 ${total} 条`}/> ) }); } let selectedValue = null; return ( <Select ref={search => this.$search_ = search} {...selectProps} dropdownClassName="j-com-minSearch" filterOption={(value, option) => { if (option.key === 'miniPager' || React.isValidElement(value)) { return true; } else { return option.key == value || option .props .children .toLocaleLowerCase() .indexOf(value.toLocaleLowerCase()) > -1; } }} onSelect={(value, option) => { selectedValue = value; if (value === 'miniPager') { setTimeout(() => { this.setOpenState(); }, 100); return; } let item; if (multiple) { item = list.find(item => item[rowKey] == value); this.state.multiMap[value] = item; value = this .state .value .concat(value); } else { item = { [rowKey]: option.props.value, [labelKey]: option.props.children }; } this.setState({current: 1, value: value, keyword: ''}); onChange(value, item); }} onDeselect={value => { selectedValue = null; if (multiple) { const idx = this .state .value .findIndex(v => v == value); delete this.state.multiMap[value]; value = this .state .value .slice(0, idx) .concat(this.state.value.slice(idx + 1)); this.setState({current: 1, value: value, keyword: ''}); onChange(value); } }} onChange={value => { selectedValue = null; if (value === undefined || Array.isArray(value) && !value.length) { this.getData({page: 1, keyword: '', ids: ''}); this.setState({current: 1, value: this.props.multiple ? [] : '', multiMap: {}, keyword: ''}); onChange(value); } }} onSearch={value => { if (selectedValue) return; this.handleSearch({ page: 1, keyword: value || '' }/*, () => { if (multiple && !value) { this.setOpenState(); } }*/) }}> {list.map(item => ( <Select.Option key={item[rowKey]}>{item[labelKey]}</Select.Option> ))} </Select> ) } setOpenState() { if (this.$search_._reactInternalInstance._renderedComponent._instance.setOpenState) { this .$search_ ._reactInternalInstance ._renderedComponent ._instance .setOpenState(true); } } }