import React from 'react'; import {Api} from '../../types'; import {RendererProps} from '../../factory'; import {isApiOutdated, isEffectiveApi, normalizeApi} from '../../utils/api'; import {Icon} from '../../components/icons'; import Overlay from '../../components/Overlay'; import PopOver from '../../components/PopOver'; import {findDOMNode} from 'react-dom'; import Checkbox from '../../components/Checkbox'; import xor from 'lodash/xor'; import {normalizeOptions} from '../../components/Select'; import {getVariable} from '../../utils/helper'; export interface QuickFilterConfig { options: Array; source: Api; multiple: boolean; [propName: string]: any; } export interface HeadCellFilterProps extends RendererProps { data: any; name: string; filterable: QuickFilterConfig; onQuery: (values: object) => void; } export class HeadCellFilterDropDown extends React.Component< HeadCellFilterProps, any > { state = { isOpened: false, filterOptions: [] }; sourceInvalid: boolean = false; constructor(props: HeadCellFilterProps) { super(props); this.open = this.open.bind(this); this.close = this.close.bind(this); this.handleClick = this.handleClick.bind(this); this.handleCheck = this.handleCheck.bind(this); } componentDidMount() { const {filterable, name, store} = this.props; if (filterable.source) { this.fetchOptions(); } else if (filterable.options?.length > 0) { this.setState({ filterOptions: this.alterOptions(filterable.options) }); } } componentDidUpdate(prevProps: HeadCellFilterProps, prevState: any) { const name = this.props.name; const props = this.props; if ( prevProps.name !== props.name || prevProps.filterable !== props.filterable || prevProps.data !== props.data ) { if (props.filterable.source) { this.sourceInvalid = isApiOutdated( prevProps.filterable.source, props.filterable.source, prevProps.data, props.data ); } else if (props.filterable.options) { this.setState({ filterOptions: this.alterOptions(props.filterable.options || []) }); } else if ( name && !this.state.filterOptions.length && (Array.isArray(props.store?.data.itemsRaw) || Array.isArray(props.store?.data.items)) ) { const itemsRaw = props.store?.data.itemsRaw || props.store?.data.items; const values: Array = []; itemsRaw.forEach((item: any) => { const value = getVariable(item, name); if (!~values.indexOf(value)) { values.push(value); } }); if (values.length) { this.setState({ filterOptions: this.alterOptions(values) }); } } } if ( this.props.data[name] !== prevProps.data[name] && this.state.filterOptions.length && prevState.filterOptions !== this.props.filterOptions ) { this.setState({ filterOptions: this.alterOptions(this.state.filterOptions) }); } this.sourceInvalid && this.fetchOptions(); } fetchOptions() { const {env, filterable, data} = this.props; if (!isEffectiveApi(filterable.source, data)) { return; } const api = normalizeApi(filterable.source); api.cache = 3000; // 开启 3s 缓存,因为固顶位置渲染1次会额外多次请求。 env.fetcher(api, data).then(ret => { let options = (ret.data && ret.data.options) || []; this.setState({ filterOptions: ret && ret.data && this.alterOptions(options) }); }); } alterOptions(options: Array) { const {data, filterable, name} = this.props; const filterValue = data && typeof data[name] !== 'undefined' ? data[name] : ''; options = normalizeOptions(options); if (filterable.multiple) { options = options.map(option => ({ ...option, selected: filterValue.split(',').indexOf(option.value) > -1 })); } else { options = options.map(option => ({ ...option, selected: option.value == filterValue })); } return options; } handleClickOutside() { this.close(); } open() { this.setState({ isOpened: true }); } close() { this.setState({ isOpened: false }); } handleClick(value: string) { const {onQuery, name} = this.props; onQuery({ [name]: value }); this.close(); } handleCheck(value: string) { const {data, name, onQuery} = this.props; let query: string; if (data[name] && data[name] === value) { query = ''; } else { query = (data[name] && xor(data[name].split(','), [value]).join(',')) || value; } onQuery({ [name]: query }); } handleReset() { const {name, onQuery} = this.props; onQuery({ [name]: undefined }); this.close(); } render() { const {isOpened, filterOptions} = this.state; const { data, name, filterable, popOverContainer, classPrefix: ns, classnames: cx, translate: __ } = this.props; return ( {isOpened ? ( findDOMNode(this))} placement="left-bottom-left-top right-bottom-right-top" target={ popOverContainer ? () => findDOMNode(this)!.parentNode : null } show > {filterOptions && filterOptions.length > 0 ? (
    {!filterable.multiple ? filterOptions.map((option: any, index) => (
  • {option.label}
  • )) : filterOptions.map((option: any, index) => (
  • {option.label}
  • ))} {filterOptions.some((item: any) => item.selected) ? (
  • {__('reset')}
  • ) : null}
) : null}
) : null}
); } }