import React, { Component } from 'react'; import { is, List, Map } from 'immutable'; import classname from 'classnames' import * as Tools from 'jad-tool' import { Checkbox, Icon, Row, Col, AutoComplete, Input, Empty } from 'antd' import { PageComponent } from '../../../types/index'; import { throttle } from 'jad-tool' import { Cascader, initOptionsType, cascaderOptionsItemType } from '../util' const { Option: AutoOption } = AutoComplete; const { Search } = Input; export type quickOptionsType = { name: string, options: cascaderOptionsItemType[], index?: number, } const ROOT_SHOW_OPTIONS = 0 export class CascaderTree extends Component cascaderOptionsItemType[] propValue?: string propName?: string quickOptions?: quickOptionsType[] onCreateQuickOptions?: (options: cascaderOptionsItemType[]) => quickOptionsType[], value?: string[], disabled?: boolean, onChange?: (value: string[]) => void, showSearch?: boolean, searchProps?: { [propName: string]: any }, showSearchFormat?: 'ALL' | 'SELF', // 默认 ALL —— 放在 search 面板 里面或者展示里面,去 state.selectedMap 中的propName [propName: string]: any }>> { cascader = null selectWrapRef = null; state = { selectMap: [], showOptions: [], showMap: {}, quickOptions: null, flatOptions: [], searchFlatOption: [], searchValue: undefined } componentDidMount() { this.init() } UNSAFE_componentWillReceiveProps(nextProps) { if (this.props.options && !this.props.options.length && nextProps.options.length) { setTimeout(() => this.init()) } if (!this.props.value && nextProps.value) { setTimeout(() => this.resetSelect()) } } shouldComponentUpdate(nextProps, nextState) { const { options, quickOptions, value } = nextProps; if ((is(Map(nextProps), Map(this.props)) && is(Map(nextState), Map(this.state)))) { return false } return true } init() { const { options = [], onCreateInitOptions } = this.props this.cascader = new Cascader({ initOptions: options, onCreateInitOptions }) this.createQuickOptions() this.initShowOptions() } initShowOptions() { var showOptions = [] showOptions.push(this.cascader.getCollectData()) this.setState({ showOptions, flatOptions: this.cascader.flatOptions, }) } resetSelect() { const { value } = this.props var { showOptions = [] } = this.state const selectMap = this.cascader.resetOptions(value) showOptions[0] = this.cascader.getCollectData() this.setState({ selectMap, showOptions, flatOptions: this.cascader.flatOptions, }, () => { this.resetQuickStatus() }) } createQuickOptions() { var { quickOptions, onCreateQuickOptions } = this.props if (!quickOptions && !onCreateQuickOptions) return; quickOptions = quickOptions ? quickOptions : onCreateQuickOptions(this.cascader.getFlatCollectData()) quickOptions = quickOptions.sort((a, b) => { const preIndex = a.index ? a.index : 0; const currentIndex = b.index ? b.index : 0 return preIndex > currentIndex ? 1 : 0 }) this.setState({ quickOptions }) } resetQuickStatus() { let { propValue = 'value' } = this.props let { quickOptions, selectMap } = this.state if (!quickOptions || Tools.isEmptyArray(quickOptions)) { return null; } var selectMapBuff = this.cascader.coolect(selectMap) quickOptions = quickOptions.map(item => { let checked = item.options.every(e => selectMapBuff.some(i => i[propValue] === e[propValue])) let indeterminate = checked ? false : ( item.options.some(e => selectMapBuff.some(i => i[propValue] === e[propValue])) ? true : false ); return { ...item, checked, indeterminate, } }) this.setState({ quickOptions }) } onEmitChange() { const { selectMap } = this.state const { onChange, propValue = 'value' } = this.props; onChange(selectMap.map(e => e[propValue])) } onSelect(checked, record) { const selectMap = this.cascader.activeSelect(checked, record) //显示选中的子集 const newShowMap = {}; const newShowOptions = []; const _this= this; //从根节点更新数据 newShowOptions[ROOT_SHOW_OPTIONS] = this.cascader.getCollectData() // 有可能是查询 search到非当前展示list的内容 function walkParent(r) { newShowMap[r['level']] = r; if (r && r['children'] && r['children'].length) { newShowOptions[r.level+1] = _this.cascader.getCollectData(r) } if (r && r['parent']) { walkParent(r['parent']) } } walkParent(record) this.setState({ showMap: newShowMap, showOptions: newShowOptions, selectMap, flatOptions: this.cascader.flatOptions, }, () => { this.resetQuickStatus() this.onEmitChange() }) } onQuickSelect(checked, record, index) { let { quickOptions, showOptions } = this.state var selectMap = [] record.indeterminate = false; record.checked = checked record.options.map((item) => { selectMap = this.cascader.activeSelect(checked, item) }) quickOptions[index] = record //从根节点更新数据 showOptions[ROOT_SHOW_OPTIONS] = this.cascader.getCollectData() this.setState({ selectMap, showOptions, quickOptions, flatOptions: this.cascader.flatOptions, }, () => { this.onEmitChange() }) } onAddShowOptions(item, index, options) { var { showOptions, showMap } = this.state const newShowOptions = [...showOptions]; const newShowMap = {...showMap}; if (!newShowOptions[index]) { newShowOptions.splice(index, 0, options) } else { newShowOptions.splice(index, newShowOptions.length, options) } newShowMap[item.level] = item this.setState({ showOptions: newShowOptions, showMap: newShowMap }) } onClear(record) { this.onSelect(false, record) } onClearAll() { var { selectMap } = this.state selectMap.forEach(item => { selectMap = this.cascader.activeSelect(false, item) }) this.initShowOptions() this.setState({ selectMap, }, () => { this.resetQuickStatus() this.onEmitChange() }) } /* 快捷选择的数据结构只有二级,直接children对应数据最下层children */ renderQuickSelect() { let { quickOptions } = this.state; const { disabled = false } = this.props if (!quickOptions || Tools.isEmptyArray(quickOptions)) { return null; } return (
快捷选择: { quickOptions.map((item, index) => ( this.onQuickSelect(!item.checked, item, index)} checked={item.checked} key={item.name} disabled={disabled} indeterminate={item.indeterminate} >{item.name} )) }
) } renderSelectList = () => { const { selectMap } = this.state const { propName = "name", disabled = false } = this.props var selectList = selectMap if (!selectList || !selectList.length) return null; return (
this.selectWrapRef = ref} >
已选择:
{ selectMap.map(e => { return {e[propName]} {!disabled ? this.onClear(e)} /> : } }) } this.onClearAll()}>清空
) } onSearchSelect = (val, option) => { if(val === 'no-data') return if (option && option.props && option.props.record) this.onSelect(true, option.props.record || {}) } @throttle(300) onSearch(val) { const { propName = "name" } = this.props; const { flatOptions } = this.state; const searchFlatOption = val ? flatOptions.filter(item => item[propName].includes(val)) : []; // 内容清空时表示不查询 this.setState({ searchFlatOption, searchValue: val }); } renderSearchDataSource = () => { const { searchFlatOption, searchValue } = this.state; const { propValue = 'value', propName = "name", showSearchFormat } = this.props; if (Tools.isEmptyArray(searchFlatOption)) return [] if (showSearchFormat === 'ALL') { const Node = (searchFlatOption.map(item => { const selected = !!item['checked']; return {item['fullName'].map((f, index) => { return ( {index ? ` / ` : null} {!selected ? f.split(searchValue).map((e, i) => { return {i ? {searchValue} : null} {e} }) : f} ) })} })) return Node } else { const Node = (searchFlatOption.map(item => { const selected = !!item['checked']; return {!selected ? item[propName].split(searchValue).map((e, i) => { return {i ? {searchValue} : null} {e} }) : item[propName]} })) return Node } } renderSearch = () => { const { searchProps = {}, propValue = 'value', propName = "name", className } = this.props; return } renderContext = () => { const { showOptions } = this.state; return
{ showOptions.map((item, index) => { return {this.renderItem(item)} }) }
} renderItem = (options) => { const { propValue = 'value', propName = "name", disabled = false } = this.props const { showMap } = this.state; return ( ) } render() { const { showSearch, value } = this.props; return (
{this.renderSelectList()} {this.renderQuickSelect()} {showSearch && this.renderSearch()}
{this.renderContext()}
) } }