1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/open-hand-choerodon-ui

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Это зеркальный репозиторий, синхронизируется ежедневно с исходного репозитория.
Клонировать/Скачать
FilterSelect.tsx 18 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
xilang Отправлено 3 лет назад dd9b262
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
import React, { Component, Key, MouseEventHandler, ReactElement } from 'react';
import { findDOMNode } from 'react-dom';
import Icon from '../icon';
import { ColumnProps, TableStateFilters } from './interface';
import Select, { LabeledValue, OptionProps } from '../select';
import { filterByInputValue, getColumnKey } from './util';
import Checkbox from '../checkbox/Checkbox';
import { SelectMode } from '../select/enum';
import ConfigContext, { ConfigContextValue } from '../config-provider/ConfigContext';
const { Option, OptGroup } = Select;
const PAIR_SPLIT = ':';
const VALUE_SPLIT = '';
const OPTION_OR = 'option-or';
export const VALUE_OR = 'OR';
function pairValue<T>(column: ColumnProps<T>, value = '') {
const { filters } = column;
const found = filters && filters.find(filter => String(filter.value) === value);
return {
key: `${getColumnKey(column)}${PAIR_SPLIT}${value}`,
label: [column.filterTitle || column.title, PAIR_SPLIT, ' ', found ? found.text : value],
};
}
function barPair(value: string, index: number) {
return {
key: `${value}${PAIR_SPLIT}${index}`,
label: [value],
};
}
export interface FilterSelectProps<T> {
prefixCls?: string;
placeholder?: string;
dataSource?: T[];
filters?: string[];
columnFilters?: TableStateFilters<T>;
columns?: ColumnProps<T>[];
onFilter?: (column: ColumnProps<T>, nextFilters: string[]) => void;
onChange?: (filters?: any[]) => void;
onClear?: () => void;
multiple?: boolean;
getPopupContainer?: (triggerNode?: Element) => HTMLElement;
}
export interface FilterSelectState<T> {
columns: ColumnProps<T>[];
filters: string[];
columnFilters: TableStateFilters<T>;
selectColumn?: ColumnProps<T>;
inputValue: string;
checked: any[];
}
function removeDoubleOr(filters: LabeledValue[]): LabeledValue[] {
return filters.filter(({ label }, index) => label !== VALUE_OR || label !== filters[index + 1]);
}
export default class FilterSelect<T> extends Component<FilterSelectProps<T>, FilterSelectState<T>> {
static get contextType(): typeof ConfigContext {
return ConfigContext;
}
static displayName = 'FilterSelect';
context: ConfigContextValue;
constructor(props) {
super(props);
this.state = {
columns: this.getColumnsWidthFilters(),
filters: props.filters || [],
columnFilters: props.columnFilters || {},
inputValue: '',
selectColumn: undefined,
checked: [],
};
}
state: FilterSelectState<T>;
rcSelect: any;
columnRefs: any = {};
componentWillReceiveProps(nextProps: FilterSelectProps<T>) {
this.setState({
columns: this.getColumnsWidthFilters(nextProps),
});
if (nextProps.filters) {
this.setState({
filters: nextProps.filters,
});
}
if (nextProps.columnFilters) {
this.setState({
columnFilters: nextProps.columnFilters,
});
}
}
getPrefixCls() {
const { prefixCls } = this.props;
return `${prefixCls}-filter-select`;
}
handleDropdownMouseDown: MouseEventHandler<any> = e => {
e.preventDefault();
this.rcSelect.focus();
};
render() {
const { placeholder, getPopupContainer } = this.props;
const { inputValue } = this.state;
const prefixCls = this.getPrefixCls();
const multiple = this.isMultiple();
return (
<div className={prefixCls}>
<div className={`${prefixCls}-icon`}>
<Icon type="filter_list" />
</div>
<Select
ref={this.saveRef}
mode={SelectMode.tags}
filterOption={false}
onChange={this.handleChange}
onSelect={multiple ? this.handleSelect : undefined}
onInput={this.handleInput}
onInputKeyDown={this.handleInputKeyDown}
onClear={this.handleClear}
value={this.getValue()}
placeholder={placeholder}
notFoundContent={false}
showNotFindInputItem={false}
showNotFindSelectedItem={false}
dropdownMatchSelectWidth={false}
defaultActiveFirstOption={!inputValue}
dropdownStyle={{ minWidth: 256 }}
onDropdownMouseDown={this.handleDropdownMouseDown}
dropdownClassName={`${prefixCls}-dropdown`}
getRootDomNode={this.getRootDomNode}
showCheckAll={false}
onChoiceItemClick={this.handleChoiceItemClick}
getPopupContainer={getPopupContainer}
allowClear
labelInValue
blurChange
border={false}
>
{this.getOptions()}
</Select>
<div className={`${prefixCls}-columns`}>{this.renderColumnsTitle()}</div>
</div>
);
}
renderColumnsTitle() {
const { columns } = this.state;
this.columnRefs = {};
return columns.map(col => {
const key = getColumnKey(col);
return (
<span ref={this.saveColumnRef.bind(this, key)} key={key}>
{col.filterTitle || col.title}
</span>
);
});
}
isMultiple() {
const { selectColumn } = this.state;
if (selectColumn) {
return selectColumn.filterMultiple;
}
return false;
}
saveRef = (node: any) => {
if (node) {
this.rcSelect = node.rcSelect;
}
};
saveColumnRef = (key: Key, node: any) => {
if (node) {
this.columnRefs[key] = node;
}
};
handleInputKeyDown = (e: any) => {
const { value } = e.target;
const { filters, columnFilters, selectColumn } = this.state;
let filterText = value;
if (selectColumn && value) {
filterText = value.split(this.getColumnTitle(selectColumn)).slice(1);
}
if (e.keyCode === 13 && filterText[0]) {
if (selectColumn) {
const key = getColumnKey(selectColumn);
if (key) {
const { filters: columFilters } = selectColumn;
columnFilters[key] = filterText;
const found = columFilters && columFilters.find(filter => filter.text === filterText[0]);
const filterValue = found ? String(found.value) : filterText[0];
this.fireColumnFilterChange(key, [filterValue]);
}
} else {
filters.push(value);
this.fireChange(filters);
}
this.setState({
inputValue: '',
filters,
columnFilters,
selectColumn: undefined,
});
this.rcSelect.setState({
inputValue: '',
});
}
};
handleInput = (value: string) => {
let { selectColumn } = this.state;
if (selectColumn) {
if (value.indexOf(this.getColumnTitle(selectColumn)) === -1) {
selectColumn = undefined;
}
}
this.setState({
selectColumn,
inputValue: value,
});
};
handleChoiceItemClick = ({ key }: LabeledValue) => {
const pair = key.split(PAIR_SPLIT);
if (pair.length > 1) {
const columnKey = pair.shift();
const selectColumn = this.findColumn(columnKey as string);
if (selectColumn && selectColumn.filterMultiple) {
const { filters } = selectColumn;
const checked = pair
.join(PAIR_SPLIT)
.split(VALUE_SPLIT)
.map(text => {
const found = filters && filters.find(filter => filter.text === text);
return found ? found.value : text;
});
this.setState({
selectColumn,
checked,
});
}
}
};
handleSelect = ({ key }: LabeledValue) => {
const { checked, selectColumn } = this.state;
if (key === '__ok__') {
this.handleMultiCheckConfirm();
} else if (key !== `${selectColumn && selectColumn.title}:`) {
const index = checked.indexOf(key);
if (index === -1) {
checked.push(key);
} else {
checked.splice(index, 1);
}
this.setState(
{
checked,
},
() => {
if (selectColumn) {
const { columnFilters } = this.state;
const columnKey = getColumnKey(selectColumn);
if (columnKey) {
const filters = columnFilters[columnKey];
if (!filters || !filters.length) {
this.rcSelect.setState({
inputValue: this.getColumnTitle(selectColumn),
});
}
}
}
},
);
}
return false;
};
handleMultiCheckConfirm = () => {
const { selectColumn, checked } = this.state;
if (selectColumn) {
const columnKey = getColumnKey(selectColumn);
if (columnKey) {
this.fireColumnFilterChange(columnKey, checked);
this.setState({
selectColumn: undefined,
checked: [],
});
this.rcSelect.setState({
inputValue: '',
});
}
}
};
handleClear = () => {
this.setState({ selectColumn: undefined });
};
handleChange = (changedValue: LabeledValue[]) => {
const { state, rcSelect } = this;
const { selectColumn, inputValue, columnFilters } = state;
let { filters } = state;
const all = this.getValue();
let change = false;
if (changedValue.length > all.length) {
const value = changedValue.pop();
if (inputValue && value && value.key === inputValue) {
change = true;
if (selectColumn && !selectColumn.filterMultiple && value) {
const columnKey = getColumnKey(selectColumn);
const columnTitle = this.getColumnTitle(selectColumn);
const val = rcSelect.state.inputValue || value.key;
if (columnKey) {
this.fireColumnFilterChange(columnKey, [val.split(`${columnTitle}`)[1]]);
}
} else {
filters.push(value.label as string);
}
this.setState({
selectColumn: undefined,
inputValue: '',
filters,
});
} else if (value && value.label === OPTION_OR) {
filters.push(VALUE_OR);
change = true;
this.setState({
filters,
});
} else if (selectColumn) {
if (!selectColumn.filterMultiple) {
const columnKey = getColumnKey(selectColumn);
if (rcSelect.state.inputValue && value && columnKey) {
this.fireColumnFilterChange(columnKey, (selectColumn.filters && !selectColumn.filters.length && !inputValue) ? [] : [value.key]);
}
this.setState({
selectColumn: undefined,
});
} else {
this.setState({
selectColumn: undefined,
checked: [],
});
rcSelect.setState({
inputValue: '',
});
}
} else if (value) {
const column = this.findColumn(value.key);
const columnFilter = columnFilters[value.key];
if (column && (!columnFilter || !columnFilter.length)) {
rcSelect.setState({
inputValue: this.getColumnTitle(column),
});
}
this.setState({
selectColumn: column,
});
}
} else {
filters = this.changeValue(changedValue, rcSelect.state.value);
if (state.filters.length !== filters.length) {
change = true;
}
this.setState({
inputValue: '',
filters,
});
}
if (change) {
this.fireChange(filters);
}
};
fireChange(filters: any[]) {
const { onChange } = this.props;
if (typeof onChange === 'function') {
onChange(filters);
}
}
fireColumnFilterChange(columnKey: string | number, value: any[]) {
const col = this.findColumn(columnKey);
const { onFilter } = this.props;
if (col && onFilter) {
onFilter(col, value || null);
}
}
changeValue(changedValue: LabeledValue[], oldValue: any[]): string[] {
const { state } = this;
const changedColumnKeys: any[] = [];
const changedColumnFilters = state.columnFilters;
const columnFiltersValues = this.getColumnFiltersValues();
if (changedValue.length) {
const len = columnFiltersValues.length;
if (len > 0) {
const index = oldValue.findIndex(
(item, i) => item !== (changedValue[i] && changedValue[i].key),
);
if (index < columnFiltersValues.length) {
const deleted = changedValue.splice(0, len - 1);
if (deleted.length < 2 && changedValue[0] && changedValue[0].label === VALUE_OR) {
changedValue.shift();
}
let value = columnFiltersValues[index];
if (value === VALUE_OR) {
value = columnFiltersValues[index + 1];
}
const columnKey = Object.keys(value)[0];
const columnFilters = changedColumnFilters[columnKey].slice();
const column = this.findColumn(columnKey);
if (column) {
const { filters } = column;
value[columnKey].split(VALUE_SPLIT).forEach((text: string) => {
const found = filters && filters.find(filter => filter.text === text);
const filterIndex = columnFilters.indexOf(found ? found.value : text);
if (filterIndex !== -1) {
columnFilters.splice(filterIndex, 1);
changedColumnFilters[columnKey] = columnFilters;
if (changedColumnKeys.indexOf(columnKey) === -1) {
changedColumnKeys.push(columnKey);
}
}
});
}
} else {
changedValue.splice(0, len);
}
}
changedColumnKeys.forEach(key => {
this.fireColumnFilterChange(key, changedColumnFilters[key]);
});
} else {
const { onClear } = this.props;
if (onClear) {
onClear();
}
}
return removeDoubleOr(changedValue).map(item => {
const label: any = item.label;
if (label.constructor === Array) {
return label && label[0];
}
return label;
});
}
getColumnFiltersValues() {
const values: any[] = [];
const { columnFilters } = this.state;
Object.keys(columnFilters).forEach(c => {
const filteredValue = columnFilters[c];
const column = this.findColumn(c);
if (filteredValue && filteredValue.length && column) {
const { filters } = column;
values.push({
[c]: filteredValue
.map(value => {
const found =
filters && filters.find(filter => String(filter.value) === String(value));
return found ? found.text : value;
})
.join(VALUE_SPLIT),
});
}
});
return values;
}
getValue() {
const { filters } = this.state;
return this.getColumnFiltersValues()
.map(this.toValueString)
.concat(filters.map(barPair));
}
getInputFilterOptions(inputValue: string) {
const { columns, dataSource } = this.props;
const options: ReactElement<OptionProps>[] = [];
if (dataSource && columns) {
const values: { [x: string]: boolean } = {};
filterByInputValue<T>(
dataSource,
columns,
inputValue,
(record: T, column: ColumnProps<T>) => {
const { dataIndex } = column;
if (dataIndex) {
const value = (record as any)[dataIndex].toString();
if (!values[value]) {
values[value] = true;
options.push(
<Option key={value} value={value}>
{value}
</Option>,
);
}
}
},
);
}
return options;
}
getOptions() {
const { state } = this;
const { selectColumn, inputValue, columns, checked, columnFilters } = state;
if (selectColumn) {
if (inputValue && inputValue.split(PAIR_SPLIT)[1]) {
return null;
}
const { filters, filterMultiple } = selectColumn;
const columnKey = getColumnKey(selectColumn);
if (filters) {
return filters
.filter(filter => !filter.children)
.map((filter, i) => {
const value = String(filter.value);
let text: any = filter.text;
if (filterMultiple && columnKey) {
let _checked = columnFilters[columnKey];
if (_checked && !checked.length) {
state.checked = _checked.slice();
} else {
_checked = checked;
}
text = [
<Checkbox key="ck" className="multiple" checked={_checked.indexOf(value) !== -1} />,
text,
];
}
return (
<Option key={`filter-${String(i)}`} value={value}>
{text}
</Option>
);
})
.concat(
filterMultiple ? (
<OptGroup key="ok">
<Option value="__ok__" className={`${this.getPrefixCls()}-ok-btn`}>
确认
</Option>
</OptGroup>
) : (
[]
),
);
}
} else if (inputValue) {
return this.getInputFilterOptions(inputValue);
} else {
const { filters } = this.state;
const { multiple } = this.props;
const { length } = filters;
const value = this.getColumnFiltersValues();
const keys = value.map(item => Object.keys(item)[0]);
const options = columns.reduce((opts: any[], column, i) => {
const key = getColumnKey(column, i);
if (keys.indexOf(key as string) === -1 || column.filterMultiple) {
opts.push(
<Option key={`column-${key}`} value={key}>
<span>{column.filterTitle || column.title}</span>
</Option>,
);
}
return opts;
}, []);
if (multiple && (length ? filters[length - 1] !== VALUE_OR : value.length)) {
return [
<OptGroup key="or">
<Option value={OPTION_OR}>OR</Option>
</OptGroup>,
<OptGroup key="all">{options}</OptGroup>,
];
}
return options;
}
}
getColumnsWidthFilters(props = this.props) {
return (props.columns || []).filter(column => column.filters instanceof Array);
}
findColumn(myKey: string | number) {
const { columns } = this.state;
return columns.find(c => getColumnKey(c) === myKey);
}
toValueString = (item: any) => {
const key = Object.keys(item)[0];
const col = this.findColumn(key);
if (col) {
return pairValue(col, item[key]);
}
return '';
};
getRootDomNode = (): HTMLElement => {
const { getPrefixCls } = this.context;
return (findDOMNode(this) as HTMLElement).querySelector(
`.${getPrefixCls('select')}-search__field`,
) as HTMLElement;
};
getColumnTitle(column: ColumnProps<T>) {
const columnKey = getColumnKey(column);
if (columnKey) {
return `${this.columnRefs[columnKey].textContent}${PAIR_SPLIT}`;
}
return '';
}
}

Комментарий ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/open-hand-choerodon-ui.git
git@gitlife.ru:oschina-mirror/open-hand-choerodon-ui.git
oschina-mirror
open-hand-choerodon-ui
open-hand-choerodon-ui
master