foundation.ts 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
  1. /* eslint-disable prefer-destructuring */
  2. /* eslint-disable max-depth */
  3. /* eslint-disable max-nested-callbacks */
  4. /* eslint-disable max-len */
  5. /* eslint-disable no-param-reassign */
  6. /* eslint-disable eqeqeq */
  7. /* eslint-disable @typescript-eslint/no-empty-function */
  8. import {
  9. get,
  10. merge,
  11. isFunction,
  12. each,
  13. find,
  14. some,
  15. pull,
  16. isSet,
  17. filter,
  18. isMap,
  19. slice,
  20. isEqual,
  21. isUndefined
  22. } from 'lodash';
  23. import memoizeOne from 'memoize-one';
  24. import { ArrayElement } from '../utils/type';
  25. import { BaseCheckboxProps } from '../checkbox/checkboxFoundation';
  26. import BaseFoundation, { DefaultAdapter } from '../base/foundation';
  27. import { strings, numbers } from './constants';
  28. import { mergeQueries, flattenColumns, filterColumns } from './utils';
  29. import { pullAll, withOrderSort } from '../utils/array';
  30. export interface BaseColumnProps<RecordType> {
  31. align?: BaseAlign;
  32. children?: Array<BaseColumnProps<RecordType>>;
  33. className?: string;
  34. colSpan?: number;
  35. dataIndex?: string;
  36. defaultFilteredValue?: any[];
  37. defaultSortOrder?: BaseSortOrder;
  38. filterChildrenRecord?: boolean;
  39. filterDropdown?: any;
  40. filterDropdownProps?: Record<string, any>;
  41. filterDropdownVisible?: boolean;
  42. filterIcon?: any;
  43. filterMultiple?: boolean;
  44. filteredValue?: any[];
  45. filters?: BaseFilter[];
  46. fixed?: BaseFixed;
  47. key?: string | number;
  48. onCell?: BaseOnCell<RecordType>;
  49. onFilter?: BaseOnFilter<RecordType>;
  50. onFilterDropdownVisibleChange?: BaseOnFilterDropdownVisibleChange;
  51. onHeaderCell?: BaseOnHeaderCell<RecordType>;
  52. render?: (...args: any[]) => any;
  53. renderFilterDropdownItem?: (...args: any[]) => any;
  54. sortChildrenRecord?: boolean;
  55. sortOrder?: BaseSortOrder;
  56. sorter?: BaseSorter<RecordType>;
  57. title?: any;
  58. useFullRender?: boolean;
  59. width?: string | number
  60. }
  61. export interface TableAdapter<RecordType> extends DefaultAdapter {
  62. resetScrollY: () => void;
  63. setSelectedRowKeys: (selectedRowKeys: BaseRowKeyType[]) => void;
  64. setDisabledRowKeys: (disabledRowKeys: BaseRowKeyType[]) => void;
  65. setCurrentPage: (currentPage: number) => void;
  66. setPagination: (pagination: BasePagination) => void;
  67. setGroups: (groups: Map<string, RecordType[]>) => void;
  68. setDataSource: (dataSource: RecordType[]) => void;
  69. setExpandedRowKeys: (expandedRowKeys: BaseRowKeyType[]) => void;
  70. setQuery: (query?: BaseColumnProps<RecordType>) => void;
  71. setQueries: (queries: BaseColumnProps<RecordType>[]) => void;
  72. setFlattenData: (flattenData: RecordType[]) => void;
  73. setAllRowKeys: (allRowKeys: BaseRowKeyType[]) => void;
  74. setHoveredRowKey: (hoveredRowKey: BaseRowKeyType) => void;
  75. setCachedFilteredSortedDataSource: (filteredSortedDataSource: RecordType[]) => void;
  76. setCachedFilteredSortedRowKeys: (filteredSortedRowKeys: BaseRowKeyType[]) => void;
  77. getCurrentPage: () => number;
  78. getCurrentPageSize: () => number;
  79. getCachedFilteredSortedDataSource: () => RecordType[];
  80. getCachedFilteredSortedRowKeys: () => BaseRowKeyType[];
  81. getCachedFilteredSortedRowKeysSet: () => Set<BaseRowKeyType>;
  82. setAllDisabledRowKeys: (allDisabledRowKeys: BaseRowKeyType[]) => void;
  83. getAllDisabledRowKeys: () => BaseRowKeyType[];
  84. getAllDisabledRowKeysSet: () => Set<BaseRowKeyType>;
  85. notifyFilterDropdownVisibleChange: (visible: boolean, dataIndex: string) => void;
  86. notifyChange: (changeInfo: { pagination: BasePagination; filters: BaseChangeInfoFilter<RecordType>[]; sorter: BaseChangeInfoSorter<RecordType>; extra: any }) => void;
  87. notifyExpand: (expanded?: boolean, record?: BaseIncludeGroupRecord<RecordType>, mouseEvent?: any) => void;
  88. notifyExpandedRowsChange: (expandedRows: BaseIncludeGroupRecord<RecordType>[]) => void;
  89. notifySelect: (record?: BaseIncludeGroupRecord<RecordType>, selected?: boolean, selectedRows?: BaseIncludeGroupRecord<RecordType>[], nativeEvent?: any) => void;
  90. notifySelectAll: (selected?: boolean, selectedRows?: BaseIncludeGroupRecord<RecordType>[], changedRows?: BaseIncludeGroupRecord<RecordType>[], e?: any) => void;
  91. notifySelectInvert: (record?: RecordType[], selected?: boolean, selectedRows?: BaseIncludeGroupRecord<RecordType>[], nativeEvent?: any) => void;
  92. notifySelectionChange: (selectedRowKeys: BaseRowKeyType[], selectedRows: BaseIncludeGroupRecord<RecordType>[]) => void;
  93. isAnyColumnFixed: (columns?: BaseColumnProps<RecordType>[]) => boolean;
  94. useFixedHeader: () => boolean;
  95. setHeadWidths: (headWidths: Array<BaseHeadWidth>, index?: number) => void;
  96. getHeadWidths: (index?: number) => number[];
  97. getCellWidths: (flattenedColumns: BaseColumnProps<RecordType>[], flattenedWidths?: BaseHeadWidth[], ignoreScrollBarKey?: boolean) => number[];
  98. mergedRowExpandable: (record: RecordType) => boolean;
  99. isAnyColumnUseFullRender: (columns: BaseColumnProps<RecordType>[]) => boolean;
  100. getNormalizeColumns: () => (columns: BaseColumnProps<RecordType>[], children: any) => BaseColumnProps<RecordType>[];
  101. getHandleColumns: () => (queries: BaseColumnProps<RecordType>[], cachedColumns: BaseColumnProps<RecordType>[]) => BaseColumnProps<RecordType>[];
  102. getMergePagination: () => (pagination: BasePagination) => BasePagination;
  103. setBodyHasScrollbar: (bodyHasScrollBar: boolean) => void
  104. }
  105. class TableFoundation<RecordType> extends BaseFoundation<TableAdapter<RecordType>> {
  106. memoizedWithFnsColumns: (
  107. queries: BaseColumnProps<RecordType>[],
  108. cachedColumns: BaseColumnProps<RecordType>[],
  109. rowSelectionUpdate: boolean,
  110. hideExpandedColumn: boolean,
  111. bodyHasScrollBar: boolean,
  112. ) => BaseColumnProps<RecordType>[];
  113. memoizedFilterColumns: (columns: BaseColumnProps<RecordType>[], ignoreKeys?: string[]) => BaseColumnProps<RecordType>[];
  114. memoizedFlattenFnsColumns: (columns: BaseColumnProps<RecordType>[], childrenColumnName?: string) => BaseColumnProps<RecordType>[];
  115. memoizedPagination: (pagination: BasePagination) => BasePagination;
  116. /**
  117. * update columns in place, and use default values as initial values if the sorting and filtering columns have no values
  118. */
  119. static initColumnsFilteredValueAndSorterOrder(columns: BaseColumnProps<unknown>[]) {
  120. columns.forEach(column => {
  121. TableFoundation.initFilteredValue(column);
  122. TableFoundation.initSorterOrder(column);
  123. });
  124. return columns;
  125. }
  126. /**
  127. * init filteredValue of filtering column, use defaultFilteredValue or [] when it is undefined
  128. */
  129. static initFilteredValue(column: BaseColumnProps<unknown>) {
  130. const { defaultFilteredValue, filteredValue, onFilter } = column;
  131. const hasFilter = isFunction(onFilter);
  132. if (hasFilter && isUndefined(filteredValue)) {
  133. if (Array.isArray(defaultFilteredValue) && defaultFilteredValue.length) {
  134. column.filteredValue = defaultFilteredValue;
  135. } else {
  136. column.filteredValue = [];
  137. }
  138. }
  139. }
  140. /**
  141. * init sortOrder of sorting column, use defaultSortOrder or [] when it is undefined
  142. */
  143. static initSorterOrder(column: BaseColumnProps<unknown>) {
  144. const { defaultSortOrder, sortOrder, sorter } = column;
  145. if (sorter && isUndefined(sortOrder)) {
  146. if (!isUndefined(defaultSortOrder)) {
  147. column.sortOrder = defaultSortOrder;
  148. } else {
  149. column.sortOrder = false;
  150. }
  151. }
  152. }
  153. constructor(adapter: TableAdapter<RecordType>) {
  154. super({ ...adapter });
  155. /**
  156. * memoized function list
  157. */
  158. const handleColumns: (queries: BaseColumnProps<RecordType>[], cachedColumns: BaseColumnProps<RecordType>[]) => BaseColumnProps<RecordType>[] = this._adapter.getHandleColumns();
  159. const mergePagination: (pagination: BasePagination) => BasePagination = this._adapter.getMergePagination();
  160. this.memoizedWithFnsColumns = memoizeOne(handleColumns, isEqual);
  161. this.memoizedFilterColumns = memoizeOne(filterColumns);
  162. this.memoizedFlattenFnsColumns = memoizeOne(flattenColumns);
  163. this.memoizedPagination = memoizeOne(mergePagination, isEqual);
  164. }
  165. init() {
  166. const dataSource = [...this.getProp('dataSource')];
  167. const { queries } = this._adapter.getStates();
  168. const filteredSortedDataSource = this.getFilteredSortedDataSource(dataSource, queries);
  169. const allDataDisabledRowKeys = this.getAllDisabledRowKeys(filteredSortedDataSource);
  170. const pageData = this.getCurrentPageData(filteredSortedDataSource);
  171. this.setAdapterPageData(pageData);
  172. this.initExpandedRowKeys(pageData);
  173. this.initSelectedRowKeys(pageData);
  174. // cache dataSource after mount, and then calculate it on demand
  175. this.setCachedFilteredSortedDataSource(filteredSortedDataSource);
  176. this.setAllDisabledRowKeys(allDataDisabledRowKeys);
  177. }
  178. initExpandedRowKeys({ groups }: { groups?: Map<string, RecordType[]> } = {}) {
  179. const {
  180. defaultExpandAllRows,
  181. defaultExpandedRowKeys = [],
  182. expandedRowKeys: propExpandedRowKeys = [],
  183. dataSource = [],
  184. expandAllRows,
  185. defaultExpandAllGroupRows,
  186. expandAllGroupRows,
  187. } = this.getProps();
  188. const expandedRowKeys: BaseRowKeyType[] = [];
  189. if (defaultExpandAllRows || expandAllRows) {
  190. this._addNoDuplicatedItemsToArr(
  191. expandedRowKeys,
  192. this.getAllRowKeys(dataSource),
  193. groups && isMap(groups) && groups.size ? Array.from(groups.keys()) : []
  194. );
  195. } else if (defaultExpandAllGroupRows || expandAllGroupRows) {
  196. this._addNoDuplicatedItemsToArr(
  197. expandedRowKeys,
  198. groups && isMap(groups) && groups.size ? Array.from(groups.keys()) : []
  199. );
  200. } else if (Array.isArray(defaultExpandedRowKeys) && defaultExpandedRowKeys.length) {
  201. this._addNoDuplicatedItemsToArr(expandedRowKeys, defaultExpandedRowKeys);
  202. } else if (Array.isArray(propExpandedRowKeys) && propExpandedRowKeys.length) {
  203. this._addNoDuplicatedItemsToArr(expandedRowKeys, propExpandedRowKeys);
  204. }
  205. this._adapter.setExpandedRowKeys(expandedRowKeys);
  206. }
  207. initSelectedRowKeys({ disabledRowKeys }: { disabledRowKeys?: BaseRowKeyType[] }) {
  208. const rowSelection = this.getProp('rowSelection');
  209. const rowKeys: BaseRowKeyType[] = [];
  210. if (rowSelection) {
  211. const selectedRowKeys = get(rowSelection, 'selectedRowKeys');
  212. const defaultSelectedRowKeys = get(rowSelection, 'defaultSelectedRowKeys');
  213. if (Array.isArray(selectedRowKeys)) {
  214. this._addNoDuplicatedItemsToArr(rowKeys, selectedRowKeys);
  215. } else if (Array.isArray(defaultSelectedRowKeys)) {
  216. this._addNoDuplicatedItemsToArr(rowKeys, defaultSelectedRowKeys);
  217. }
  218. if (Array.isArray(disabledRowKeys) && disabledRowKeys.length) {
  219. pull(rowKeys, ...disabledRowKeys);
  220. }
  221. this._adapter.setSelectedRowKeys(rowKeys);
  222. }
  223. }
  224. /**
  225. * Get filtered and sorted data
  226. * @param {Object[]} dataSource
  227. * @param {Object[]} queries
  228. * @returns {Object[]} sortedDataSource
  229. */
  230. getFilteredSortedDataSource(dataSource: RecordType[], queries: BaseColumnProps<RecordType>[]) {
  231. const filteredDataSource = this.filterDataSource(dataSource, queries.filter(
  232. query => {
  233. /**
  234. * 这里无需判断 filteredValue 是否为数组,初始化时它是 `undefined`,点击选择空时为 `[]`
  235. * 初始化时我们应该用 `defaultFilteredValue`,点击后我们应该用 `filteredValue`
  236. *
  237. * There is no need to judge whether `filteredValue` is an array here, because it is `undefined` when initialized, and `[]` when you click to select empty
  238. * When initializing we should use `defaultFilteredValue`, after clicking we should use `filteredValue`
  239. */
  240. const currentFilteredValue = query.filteredValue ? query.filteredValue : query.defaultFilteredValue;
  241. return (
  242. isFunction(query.onFilter) &&
  243. Array.isArray(currentFilteredValue) &&
  244. currentFilteredValue.length
  245. );
  246. }
  247. ));
  248. const sortedDataSource = this.sortDataSource(filteredDataSource, queries.filter(query => query && isFunction(query.sorter)));
  249. return sortedDataSource;
  250. }
  251. /**
  252. * get current page data
  253. *
  254. * @param {Array} dataSource
  255. * @param {object} pagination
  256. * @param {object} queries
  257. * @returns {{dataSource: RecordType[], groups: Map<string, Set<string>>, pagination: object, disabledRowKeys: string[], queries: BaseColumnProps[], allRowKeys: string[]}}
  258. */
  259. getCurrentPageData(dataSource?: RecordType[], pagination?: BasePagination, queries?: BaseColumnProps<RecordType>[]) {
  260. const filteredSortedDataSource = this._adapter.getCachedFilteredSortedDataSource();
  261. dataSource = dataSource == null ? [...filteredSortedDataSource] : dataSource;
  262. pagination =
  263. pagination == null ? this.getState('pagination') && { ...this.getState('pagination') } : pagination;
  264. queries = queries == null ? [...this.getState('queries')] : queries;
  265. let groups;
  266. if (this.getProp('groupBy') != null) {
  267. const { groups: groupedGroups, dataSource: groupedData } = this.groupDataSource(dataSource);
  268. dataSource = groupedData;
  269. groups = groupedGroups;
  270. }
  271. pagination = this.normalizePagination(pagination, dataSource);
  272. dataSource = this.limitPageDataSource(dataSource, pagination);
  273. const disabledRowKeys = this.getAllDisabledRowKeys(dataSource);
  274. const allRowKeys = this.getAllRowKeys(dataSource);
  275. const pageData: BasePageData<RecordType> = {
  276. dataSource,
  277. groups,
  278. pagination,
  279. disabledRowKeys,
  280. allRowKeys,
  281. queries,
  282. };
  283. return pageData;
  284. }
  285. /**
  286. * group dataSource, return grouped row keys
  287. *
  288. * @param {*[]} dataSource
  289. * @param {Function|string} groupBy
  290. */
  291. groupDataSource(dataSource: RecordType[], groupBy?: BaseGroupBy<RecordType>) {
  292. groupBy = groupBy == null ? this.getProp('groupBy') : groupBy;
  293. const groups = new Map();
  294. const newDataSource = [];
  295. if (groupBy != null) {
  296. each(dataSource, (record, index) => {
  297. const groupKey = typeof groupBy === 'function' ? groupBy(record) : get(record, groupBy);
  298. if (groupKey != null && groupKey !== '') {
  299. const recordKey = this.getRecordKey(record);
  300. let group = groups.get(groupKey);
  301. if (!isSet(group)) {
  302. group = new Set([recordKey]);
  303. groups.set(groupKey, group);
  304. } else {
  305. group.add(recordKey);
  306. }
  307. }
  308. });
  309. }
  310. if (groups && groups.size) {
  311. groups.forEach((set, key) => {
  312. if (isSet(set)) {
  313. set.forEach(realKey => {
  314. newDataSource.push(this._getRecord(realKey));
  315. });
  316. }
  317. });
  318. } else {
  319. newDataSource.push(...dataSource);
  320. }
  321. return { groups, dataSource: newDataSource };
  322. }
  323. /**
  324. * sort data
  325. *
  326. * @param {Array} dataSource
  327. * @param {Array} sorters
  328. * @returns {Array}
  329. */
  330. sortDataSource(dataSource: RecordType[], sorters: BaseSorterInfo<RecordType>[]) {
  331. each(sorters, sorterObj => {
  332. // const sorterObj = last(sorters) || {};
  333. const { sorter, sortOrder, defaultSortOrder, sortChildrenRecord } = sorterObj;
  334. const currentSortOrder = this.isSortOrderValid(sortOrder) ? sortOrder : defaultSortOrder;
  335. if (isFunction(sorter) && (currentSortOrder && strings.SORT_DIRECTIONS.includes(currentSortOrder))) {
  336. if (sortChildrenRecord) {
  337. const childrenRecordName = this.getProp('childrenRecordName');
  338. dataSource =
  339. dataSource &&
  340. dataSource.map(record => {
  341. const children = this._getRecordChildren(record);
  342. if (Array.isArray(children) && children.length) {
  343. return {
  344. ...record,
  345. [childrenRecordName]: this.sortDataSource(children, [sorterObj]),
  346. };
  347. }
  348. return record;
  349. });
  350. }
  351. dataSource.sort(withOrderSort(sorter, currentSortOrder));
  352. return false;
  353. }
  354. return undefined;
  355. });
  356. return dataSource;
  357. }
  358. /**
  359. * set page number
  360. */
  361. setPage = (currentPage: number, currentPageSize: number) => {
  362. currentPage = currentPage || this._adapter.getCurrentPage();
  363. const currentPagination = this.getState('pagination');
  364. const { dataSource, pagination, disabledRowKeys, allRowKeys } = this.getCurrentPageData(null, {
  365. ...currentPagination,
  366. currentPage,
  367. pageSize: currentPageSize,
  368. });
  369. if (!this._pagerIsControlled() && currentPage > 0) {
  370. this._adapter.setDisabledRowKeys(disabledRowKeys);
  371. this._adapter.setAllRowKeys(allRowKeys);
  372. this._adapter.setPagination(pagination);
  373. this._adapter.setDataSource(dataSource);
  374. }
  375. this._notifyChange(pagination);
  376. };
  377. /**
  378. * filter data source
  379. *
  380. * @param {*[]} dataSource
  381. * @param {*[]} filters
  382. * @returns {*[]}
  383. */
  384. filterDataSource(dataSource: RecordType[], filters: BaseChangeInfoFilter<RecordType>[]) {
  385. let filteredData: Map<string, RecordType> | null = null;
  386. let hasValidFilters = false;
  387. const childrenRecordName = this.getProp('childrenRecordName');
  388. each(filters, filterObj => {
  389. const { onFilter, filteredValue, filterChildrenRecord, defaultFilteredValue } = filterObj;
  390. const currentFilteredValue = Array.isArray(filteredValue) ? filteredValue : defaultFilteredValue;
  391. if (typeof onFilter === 'function' && Array.isArray(currentFilteredValue) && currentFilteredValue.length) {
  392. hasValidFilters = true;
  393. if (filteredData === null) {
  394. filteredData = new Map();
  395. } else {
  396. dataSource = Array.from(filteredData && filteredData.values());
  397. filteredData = new Map();
  398. }
  399. each(dataSource, record => {
  400. each(currentFilteredValue, value => {
  401. const childrenRecords = get(record, childrenRecordName);
  402. const recordKey = this.getRecordKey(record);
  403. let filteredChildren;
  404. if (Array.isArray(childrenRecords) && childrenRecords.length && filterChildrenRecord) {
  405. filteredChildren = this.filterDataSource(childrenRecords, [filterObj]);
  406. }
  407. if (Array.isArray(filteredChildren) && filteredChildren.length) {
  408. if (recordKey != null) {
  409. const children = get(filteredData.get(recordKey), childrenRecordName, []);
  410. filteredData.set(recordKey, {
  411. ...record,
  412. [childrenRecordName]: filteredChildren.reduce(
  413. (arr, cur) => {
  414. if (
  415. arr.find((item: any) => this.getRecordKey(item) === this.getRecordKey(cur)) ==
  416. null
  417. ) {
  418. arr.push(cur);
  419. }
  420. return arr;
  421. },
  422. [...children]
  423. ),
  424. });
  425. }
  426. } else if (onFilter(value, record)) {
  427. filteredData.set(recordKey, record);
  428. }
  429. });
  430. });
  431. }
  432. });
  433. if (hasValidFilters) {
  434. dataSource = Array.from(filteredData && filteredData.values());
  435. }
  436. return dataSource;
  437. }
  438. limitPageDataSource(dataSource: RecordType[], pagination: BasePagination) {
  439. dataSource = dataSource == null ? this.getProp('dataSource') : dataSource;
  440. pagination = pagination == null ? this.getState('pagination') : pagination;
  441. let pageData = dataSource;
  442. const pageNo = get(pagination, 'currentPage');
  443. if (this.getProp('pagination') !== false && pageNo && dataSource && pagination && !this._pagerIsControlled()) {
  444. const { pageSize = numbers.DEFAULT_PAGE_SIZE } = pagination;
  445. const start = (pageNo - 1) * pageSize;
  446. const end = pageNo * pageSize;
  447. pageData = slice(dataSource, start, end);
  448. }
  449. return pageData;
  450. }
  451. normalizePagination(pagination: BasePagination, dataSource: RecordType[]) {
  452. pagination = pagination == null ? this._getPagination() : pagination;
  453. dataSource = dataSource == null ? this._getDataSource() : dataSource;
  454. const propPagination = this.getProp('pagination');
  455. if (pagination) {
  456. pagination = typeof pagination === 'object' ? { ...pagination } : {};
  457. pagination = merge(
  458. {
  459. total: (dataSource && dataSource.length) || 0,
  460. pageSize: numbers.DEFAULT_PAGE_SIZE,
  461. currentPage: get(propPagination, 'defaultCurrentPage', 1),
  462. position: strings.PAGINATION_POSITIONS[0],
  463. },
  464. pagination
  465. );
  466. if (!this._pagerIsControlled()) {
  467. const total = get(propPagination, 'total', dataSource.length);
  468. const pageSize = get(propPagination, 'pageSize', pagination.pageSize);
  469. const { currentPage } = pagination;
  470. const realTotalPage = Math.ceil(total / pageSize);
  471. pagination.total = total;
  472. if (currentPage > realTotalPage) {
  473. pagination.currentPage = 1;
  474. }
  475. }
  476. }
  477. return pagination;
  478. }
  479. setAdapterPageData(pageData: BasePageData<RecordType> = {}) {
  480. const { pagination, dataSource, disabledRowKeys, allRowKeys, groups } = pageData;
  481. this._adapter.setDisabledRowKeys(disabledRowKeys);
  482. this._adapter.setAllRowKeys(allRowKeys);
  483. this._adapter.setPagination(pagination);
  484. this._adapter.setGroups(groups);
  485. this._adapter.setDataSource(dataSource);
  486. }
  487. /**
  488. * Cache related data when initializing or updating the calculated dataSource
  489. * @param {*} filteredSortedDataSource
  490. */
  491. setCachedFilteredSortedDataSource = (filteredSortedDataSource: RecordType[]) => {
  492. this._adapter.setCachedFilteredSortedDataSource(filteredSortedDataSource);
  493. const filteredSortedRowKeys = this.getAllRowKeys(filteredSortedDataSource);
  494. this._adapter.setCachedFilteredSortedRowKeys(filteredSortedRowKeys);
  495. };
  496. destroy() { }
  497. setAllDisabledRowKeys(disabledRowKeys) {
  498. this._adapter.setAllDisabledRowKeys(disabledRowKeys);
  499. }
  500. handleClick(e: any) { }
  501. handleMouseEnter(e: any) { }
  502. handleMouseLeave(e: any) { }
  503. stopPropagation(e: any) {
  504. this._adapter.stopPropagation(e);
  505. }
  506. /**
  507. * Add non-repeating elements to the array itself
  508. * @param {Array} srcArr
  509. * @param {Object} objArrs
  510. */
  511. _addNoDuplicatedItemsToArr(srcArr: any[] = [], ...objArrs: any[]) {
  512. for (const objArr of objArrs) {
  513. if (Array.isArray(objArr)) {
  514. for (const item of objArr) {
  515. if (!srcArr.includes(item)) {
  516. srcArr.push(item);
  517. }
  518. }
  519. }
  520. }
  521. return srcArr;
  522. }
  523. _notifyChange(pagination: BasePagination, filters?: BaseChangeInfoFilter<RecordType>[], sorter?: BaseChangeInfoSorter<RecordType>, extra?: RecordType) {
  524. pagination = pagination == null ? this._getPagination() : pagination;
  525. filters = filters == null ? this._getAllFilters() : filters;
  526. sorter = sorter == null ? this._getAllSorters()[0] as BaseChangeInfoSorter<RecordType> : sorter;
  527. if (get(this.getProp('scroll'), 'scrollToFirstRowOnChange')) {
  528. this._adapter.resetScrollY();
  529. }
  530. this._adapter.notifyChange({
  531. pagination: { ...pagination },
  532. filters: [...filters],
  533. sorter,
  534. extra: { ...extra },
  535. });
  536. }
  537. _rowExpansionIsControlled() {
  538. return Array.isArray(this.getProp('expandedRowKeys'));
  539. }
  540. _pagerIsControlled() {
  541. return get(this.getProp('pagination'), 'currentPage') != null;
  542. }
  543. _selectionIsControlled() {
  544. return Array.isArray(get(this.getProp('rowSelection'), 'selectedRowKeys'));
  545. }
  546. /**
  547. * Determine whether the column sorting is controlled
  548. * Controlled: the column passed the sortOrder prop
  549. * @param {String} dataIndex
  550. * @returns {Boolean}
  551. */
  552. _sorterIsControlled(dataIndex: string) {
  553. // The basis for judgment should be props columns instead of cachedColumns fix#1141
  554. const query = dataIndex && this.getQuery(dataIndex, this.getState('flattenColumns'));
  555. return Boolean(query && query.sortOrder != null);
  556. }
  557. /**
  558. * Determine whether the column is filtered and controlled
  559. * Controlled: the column passed the filteredValue prop
  560. * @param {String} dataIndex
  561. * @returns {Boolean}
  562. */
  563. _filterIsControlled(dataIndex: string) {
  564. const query = dataIndex && this.getQuery(dataIndex, this.getState('flattenColumns'));
  565. return Boolean(query && Array.isArray(query.filteredValue));
  566. }
  567. _filterShowIsControlled(dataIndex?: string) {
  568. const query = dataIndex && this.getQuery(dataIndex, this.getState('flattenColumns'));
  569. return Boolean(query && (query.filterDropdownVisible === true || query.filterDropdownVisible === false));
  570. }
  571. _getSelectedRowKeys() {
  572. const rowSelection = this.getState('rowSelection');
  573. const selectedRowKeys = get(rowSelection, 'selectedRowKeys', []);
  574. return [...selectedRowKeys];
  575. }
  576. _getSelectedRowKeysSet() {
  577. const rowSelection = this.getState('rowSelection');
  578. const selectedRowKeysSet = get(rowSelection, 'selectedRowKeysSet', new Set());
  579. return selectedRowKeysSet;
  580. }
  581. _getDataSource() {
  582. return this.getProp('dataSource') || [];
  583. }
  584. _getRecord(realKey: string | number) {
  585. return find(
  586. this.getProp('dataSource'),
  587. record => realKey != null && realKey !== '' && this.getRecordKey(record) === realKey
  588. );
  589. }
  590. _getRecordChildren(record: RecordType) {
  591. return get(record, this.getProp('childrenRecordName'));
  592. }
  593. _getPagination() {
  594. return this.getState('pagination') || {};
  595. }
  596. _getAllFilters(queries?: BaseColumnProps<RecordType>[]) {
  597. queries = queries || this.getState('queries');
  598. const filters: BaseChangeInfoFilter<RecordType>[] = [];
  599. each(queries, query => {
  600. if (
  601. Array.isArray(query.filteredValue) &&
  602. (query.filteredValue.length || this._filterIsControlled(query.dataIndex))
  603. ) {
  604. filters.push(query);
  605. }
  606. });
  607. return filters;
  608. }
  609. _getAllSorters(queries?: BaseColumnProps<RecordType>[]): BaseColumnProps<RecordType>[] {
  610. queries = queries || this.getState('queries');
  611. return filter(queries, query => query.sorter && query.sortOrder) as BaseColumnProps<RecordType>[];
  612. }
  613. _filterQueries(targetQuery: BaseColumnProps<RecordType>, queries: BaseColumnProps<RecordType>[], keys = ['dataIndex']) {
  614. queries = queries == null ? this.getState('queries') : queries;
  615. const filteredQueries: BaseColumnProps<RecordType>[] = [];
  616. const filteredIndexes: number[] = [];
  617. each(queries, (itQuery, index) => {
  618. const flag = some(keys, k => k && targetQuery[k] != null && targetQuery[k] === itQuery[k]);
  619. if (flag) {
  620. filteredQueries.push(itQuery);
  621. filteredIndexes.push(index);
  622. }
  623. });
  624. return { filteredQueries, filteredIndexes };
  625. }
  626. _mergeToQueries(query: BaseColumnProps<RecordType>, queries: BaseColumnProps<RecordType>[], keys = ['dataIndex']) {
  627. queries = queries == null ? this.getState('queries') : queries;
  628. queries = [...queries];
  629. query = { ...query };
  630. const { filteredQueries, filteredIndexes } = this._filterQueries(query, queries, keys);
  631. each(filteredQueries, (curQuery, idx) => {
  632. // assign(curQuery, query);
  633. queries[filteredIndexes[idx]] = { ...query };
  634. });
  635. return queries;
  636. }
  637. /**
  638. * get record real key
  639. * @param {RecordType} record
  640. * @returns {string}
  641. */
  642. getRecordKey(record: RecordType): string {
  643. if (!record) {
  644. return undefined;
  645. }
  646. const rowKey = this.getProp('rowKey');
  647. return typeof rowKey === 'function' ? rowKey(record) : get(record, rowKey);
  648. }
  649. isEmpty(dataSource: RecordType[]) {
  650. dataSource = dataSource == null ? this.getProp('dataSource') : dataSource;
  651. return !(Array.isArray(dataSource) && dataSource.length > 0);
  652. }
  653. handleSelectRow(realKey: BaseRowKeyType, selected: boolean, e: any) {
  654. this.stopPropagation(e);
  655. if (typeof selected === 'boolean' && realKey != null) {
  656. const selectedRowKeys = this._getSelectedRowKeys();
  657. let foundIdx = -1;
  658. const selectedRow = this.getSelectedRows(null, [realKey])[0];
  659. let selectedRows: BaseIncludeGroupRecord<RecordType>[];
  660. if ((foundIdx = selectedRowKeys.indexOf(realKey)) > -1 && selected === false) {
  661. selectedRowKeys.splice(foundIdx, 1);
  662. selectedRows = this.getSelectedRows(null, selectedRowKeys);
  663. if (!this._selectionIsControlled()) {
  664. this._adapter.setSelectedRowKeys(selectedRowKeys);
  665. }
  666. this._adapter.notifySelect(selectedRow, selected, selectedRows, e);
  667. this._adapter.notifySelectionChange(selectedRowKeys, selectedRows);
  668. } else if (selectedRowKeys.indexOf(realKey) === -1 && selected === true) {
  669. selectedRowKeys.push(realKey);
  670. selectedRows = this.getSelectedRows(null, selectedRowKeys);
  671. if (!this._selectionIsControlled()) {
  672. this._adapter.setSelectedRowKeys(selectedRowKeys);
  673. }
  674. this._adapter.notifySelect(selectedRow, selected, selectedRows, e);
  675. this._adapter.notifySelectionChange(selectedRowKeys, selectedRows);
  676. }
  677. }
  678. }
  679. /**
  680. * select all rows
  681. * @param {*} selected The future state of the select all button
  682. * @param {*} e
  683. */
  684. handleSelectAllRow(selected: boolean, e: any) {
  685. this.stopPropagation(e);
  686. if (typeof selected === 'boolean') {
  687. const curSelectedRowKeys = this._getSelectedRowKeys();
  688. let selectedRowKeys = [...curSelectedRowKeys];
  689. const selectedRowKeysSet = this._getSelectedRowKeysSet();
  690. let allRowKeys = [...this._adapter.getCachedFilteredSortedRowKeys()];
  691. const disabledRowKeys = this._adapter.getAllDisabledRowKeys();
  692. const disabledRowKeysSet = this._adapter.getAllDisabledRowKeysSet();
  693. let changedRowKeys;
  694. // Select all, if not disabled && not in selectedRowKeys
  695. if (selected) {
  696. for (const key of allRowKeys) {
  697. if (!disabledRowKeysSet.has(key) && !selectedRowKeysSet.has(key)) {
  698. selectedRowKeys.push(key);
  699. }
  700. }
  701. allRowKeys = pullAll(allRowKeys, [...disabledRowKeys, ...curSelectedRowKeys]);
  702. changedRowKeys = [...allRowKeys];
  703. } else {
  704. selectedRowKeys = pullAll(selectedRowKeys, allRowKeys);
  705. changedRowKeys = [...curSelectedRowKeys];
  706. }
  707. const changedRows = this.getSelectedRows(null, changedRowKeys || []);
  708. const selectedRows = this.getSelectedRows(null, selectedRowKeys || []);
  709. if (!this._selectionIsControlled()) {
  710. this._adapter.setSelectedRowKeys(selectedRowKeys);
  711. }
  712. this._adapter.notifySelectAll(selected, selectedRows, changedRows, e);
  713. this._adapter.notifySelectionChange(selectedRowKeys, selectedRows);
  714. }
  715. }
  716. /**
  717. * row keys => rows
  718. * @param {*} dataSource
  719. * @param {*} selectedRowKeys
  720. * @param {*} selectedRowKeysSet Recursive optimization
  721. */
  722. getSelectedRows(dataSource: RecordType[], selectedRowKeys: BaseRowKeyType[], selectedRowKeysSet?: Set<BaseRowKeyType>): BaseIncludeGroupRecord<RecordType>[] {
  723. dataSource = dataSource == null ? this._getDataSource() : dataSource;
  724. selectedRowKeys = selectedRowKeys == null ? this._getSelectedRowKeys() : selectedRowKeys;
  725. if (!isSet(selectedRowKeysSet)) {
  726. selectedRowKeysSet = new Set(selectedRowKeys);
  727. }
  728. const childrenRecordName = this.getProp('childrenRecordName');
  729. const selectedRows: BaseIncludeGroupRecord<RecordType>[] = [];
  730. if (
  731. isSet(selectedRowKeysSet) &&
  732. selectedRowKeysSet.size &&
  733. Array.isArray(dataSource) &&
  734. dataSource.length
  735. ) {
  736. // Time complexity optimization, replace the includes operation of array with has of set
  737. selectedRows.push(...dataSource.filter(data => selectedRowKeysSet.has(this.getRecordKey(data))));
  738. if (selectedRows.length < selectedRowKeys.length) {
  739. for (const item of dataSource) {
  740. const children = get(item, childrenRecordName);
  741. if (Array.isArray(children) && children.length) {
  742. const rows = this.getSelectedRows(children, selectedRowKeys, selectedRowKeysSet);
  743. selectedRows.push(...rows);
  744. }
  745. }
  746. }
  747. }
  748. return selectedRows;
  749. }
  750. getAllDisabledRowKeys(dataSource?: RecordType[], getCheckboxProps?: GetCheckboxProps<RecordType>): BaseRowKeyType[] {
  751. dataSource = dataSource == null ? this._getDataSource() : dataSource;
  752. getCheckboxProps =
  753. getCheckboxProps == null ? get(this.getProp('rowSelection'), 'getCheckboxProps') : getCheckboxProps;
  754. const childrenRecordName = this.getProp('childrenRecordName');
  755. const disabledRowKeys: BaseRowKeyType[] = [];
  756. if (Array.isArray(dataSource) && dataSource.length && typeof getCheckboxProps === 'function') {
  757. for (const record of dataSource) {
  758. const props = getCheckboxProps(record);
  759. if (props && props.disabled) {
  760. disabledRowKeys.push(this.getRecordKey(record));
  761. }
  762. const children = get(record, childrenRecordName);
  763. if (Array.isArray(children) && children.length) {
  764. const keys: BaseRowKeyType[] = this.getAllDisabledRowKeys(children, getCheckboxProps);
  765. disabledRowKeys.push(...keys);
  766. }
  767. }
  768. }
  769. return disabledRowKeys;
  770. }
  771. getAllRowKeys(dataSource: RecordType[]): BaseRowKeyType[] {
  772. dataSource = dataSource == null ? this._getDataSource() : dataSource;
  773. const childrenRecordName = this.getProp('childrenRecordName');
  774. const allRowKeys = [];
  775. if (Array.isArray(dataSource) && dataSource.length) {
  776. for (const record of dataSource) {
  777. const childrenRowKeys = [];
  778. const children = get(record, childrenRecordName);
  779. if (Array.isArray(children) && children.length) {
  780. childrenRowKeys.push(...this.getAllRowKeys(children));
  781. }
  782. allRowKeys.push(this.getRecordKey(record), ...childrenRowKeys);
  783. }
  784. }
  785. return allRowKeys;
  786. }
  787. /**
  788. * Check if the selected item is in allRowKeysSet
  789. * @param {Array} selectedRowKeys
  790. * @param {Set} allRowKeysSet
  791. */
  792. hasRowSelected(selectedRowKeys: BaseRowKeyType[], allRowKeysSet: Set<BaseRowKeyType>) {
  793. return Boolean(Array.isArray(selectedRowKeys) &&
  794. selectedRowKeys.length &&
  795. isSet(allRowKeysSet) &&
  796. allRowKeysSet.size &&
  797. selectedRowKeys.filter(key => allRowKeysSet.has(key)).length);
  798. }
  799. /**
  800. * expand processing function
  801. * @param {Boolean} expanded
  802. * @param {String} realKey
  803. * @param {Event} domEvent
  804. */
  805. handleRowExpanded(expanded: boolean, realKey: string, domEvent: any) {
  806. this.stopPropagation(domEvent);
  807. const expandedRowKeys = [...this.getState('expandedRowKeys')];
  808. const index = expandedRowKeys.indexOf(realKey);
  809. const keyIsValid = typeof realKey === 'string' || typeof realKey === 'number';
  810. if (keyIsValid && expanded && index === -1) {
  811. expandedRowKeys.push(realKey);
  812. } else if (keyIsValid && !expanded && index > -1) {
  813. expandedRowKeys.splice(index, 1);
  814. }
  815. if (!this._rowExpansionIsControlled()) {
  816. this._adapter.setExpandedRowKeys(expandedRowKeys);
  817. }
  818. const expandedRows = this.getSelectedRows(null, expandedRowKeys);
  819. let expandedRow = this.getSelectedRows(null, [realKey])[0];
  820. // groups record processing
  821. const groups = this._getGroups();
  822. if (groups) {
  823. // Construct group expandRow
  824. if (groups.has(realKey)) {
  825. expandedRow = { groupKey: realKey };
  826. }
  827. // If expandedRowKeys includes groupKey, add to expandedRows
  828. for (let i = 0, len = expandedRowKeys.length; i < len; i++) {
  829. if (groups.has(realKey)) {
  830. expandedRows.push({ groupKey: expandedRowKeys[i] });
  831. }
  832. }
  833. }
  834. this._adapter.notifyExpand(expanded, expandedRow, domEvent);
  835. this._adapter.notifyExpandedRowsChange(expandedRows);
  836. }
  837. /**
  838. * get state.groups
  839. * @returns {Map|Null}
  840. */
  841. _getGroups() {
  842. const groupBy = this._adapter.getProp('groupBy');
  843. if (groupBy !== null) {
  844. const groups = this._adapter.getState('groups');
  845. return groups;
  846. }
  847. return null;
  848. }
  849. /**
  850. * Determine whether you have selected all except for disabled
  851. * @param {Set} selectedRowKeysSet
  852. * @param {Set} disabledRowKeysSet
  853. * @param {Array} allKeys keys after sorted and filtered
  854. */
  855. allIsSelected(selectedRowKeysSet: Set<BaseRowKeyType>, disabledRowKeysSet: Set<BaseRowKeyType>, allKeys: BaseRowKeyType[]) {
  856. const filteredAllKeys = filter(allKeys, key => key != null && !disabledRowKeysSet.has(key));
  857. if (filteredAllKeys && filteredAllKeys.length) {
  858. for (const key of filteredAllKeys) {
  859. if (key != null && !selectedRowKeysSet.has(key)) {
  860. return false;
  861. }
  862. }
  863. return true;
  864. } else {
  865. return false;
  866. }
  867. }
  868. /**
  869. * This function is not used yet
  870. * @param {*} selectedRowKeys
  871. * @param {*} allKeys
  872. */
  873. allIsNotSelected(selectedRowKeys: BaseRowKeyType[], allKeys: BaseRowKeyType[]) {
  874. for (const key of allKeys) {
  875. if (key != null && Array.isArray(selectedRowKeys) && selectedRowKeys.includes(key)) {
  876. return true;
  877. }
  878. }
  879. return false;
  880. }
  881. formatPaginationInfo(pagination: BasePagination = {}, defaultPageText = '') {
  882. let info = '';
  883. const formatPageText = get(this.getProp('pagination'), 'formatPageText');
  884. const { total, pageSize, currentPage } = pagination;
  885. const currentStart = Math.min((currentPage - 1) * pageSize + 1, total);
  886. const currentEnd = Math.min(currentPage * pageSize, total);
  887. if (formatPageText || (formatPageText !== false && defaultPageText && total > 0)) {
  888. info =
  889. typeof formatPageText === 'function' ?
  890. formatPageText({ currentStart, currentEnd, total }) :
  891. defaultPageText
  892. .replace('${currentStart}', currentStart as any)
  893. .replace('${currentEnd}', currentEnd as any)
  894. .replace('${total}', total as any);
  895. }
  896. return info;
  897. }
  898. toggleShowFilter(dataIndex: string, visible: boolean) {
  899. let filterObj: BaseColumnProps<RecordType> = this.getQuery(dataIndex);
  900. const filterDropdownVisible = visible;
  901. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  902. filterObj = { ...filterObj, filterDropdownVisible };
  903. if (!this._filterShowIsControlled()) {
  904. // this._adapter.setQuery({
  905. // ...filterObj,
  906. // filterDropdownVisible,
  907. // });
  908. }
  909. this._adapter.notifyFilterDropdownVisibleChange(filterDropdownVisible, dataIndex);
  910. }
  911. /**
  912. * Called when the filter changes
  913. * @param {*} dataIndex
  914. * @param {*} data
  915. */
  916. handleFilterSelect(dataIndex: string, data: { filteredValue?: string[] } = {}) {
  917. let query: BaseColumnProps<RecordType> = this.getQuery(dataIndex);
  918. let queries = [...this._adapter.getState('queries')];
  919. const { filteredValue } = data;
  920. query = {
  921. ...query,
  922. filteredValue,
  923. };
  924. queries = mergeQueries(query, queries);
  925. const mergedQueries = this._mergeToQueries(query, null);
  926. const filters = this._getAllFilters(mergedQueries);
  927. if (!this._filterIsControlled(dataIndex)) {
  928. this._adapter.setQueries(queries);
  929. this.handleClickFilterOrSorter(queries);
  930. }
  931. this._notifyChange(null, filters);
  932. }
  933. /**
  934. * Click the sort button to call
  935. * @param {*} column
  936. * @param {*} e
  937. */
  938. handleSort(column: { dataIndex?: string; sortOrder?: BaseSortOrder } = {}, e: any) {
  939. this.stopPropagation(e);
  940. const { dataIndex } = column;
  941. let queries = this.getState('queries');
  942. let curQuery = null;
  943. queries = [...queries];
  944. each(queries, (query, idx, arr) => {
  945. if (query.sorter) {
  946. const sorterObj = { ...query };
  947. const stateSortOrder = get(sorterObj, 'sortOrder');
  948. const defaultSortOrder = get(sorterObj, 'defaultSortOrder', false);
  949. let querySortOrder = this.isSortOrderValid(stateSortOrder) ? stateSortOrder : defaultSortOrder;
  950. if (dataIndex && dataIndex === sorterObj.dataIndex) {
  951. if (querySortOrder === strings.SORT_DIRECTIONS[0]) {
  952. querySortOrder = strings.SORT_DIRECTIONS[1];
  953. } else if (querySortOrder === strings.SORT_DIRECTIONS[1]) {
  954. querySortOrder = false;
  955. } else {
  956. querySortOrder = strings.SORT_DIRECTIONS[0];
  957. }
  958. } else {
  959. // This results in the current click only supports single column sorting
  960. querySortOrder = false;
  961. }
  962. arr[idx] = { ...sorterObj, sortOrder: querySortOrder };
  963. if (dataIndex === sorterObj.dataIndex) {
  964. curQuery = arr[idx];
  965. }
  966. }
  967. });
  968. if (!this._sorterIsControlled(dataIndex)) {
  969. this._adapter.setQueries(queries);
  970. this.handleClickFilterOrSorter(queries);
  971. }
  972. // notify sort event
  973. this._notifyChange(null, null, curQuery, null);
  974. }
  975. /**
  976. * Recalculate the cached data after clicking filter or sorter
  977. * @param {*} queries
  978. */
  979. handleClickFilterOrSorter(queries: BaseColumnProps<RecordType>[]) {
  980. const dataSource = [...this.getProp('dataSource')];
  981. const sortedDataSource = this.getFilteredSortedDataSource(dataSource, queries);
  982. const allDataDisabledRowKeys = this.getAllDisabledRowKeys(sortedDataSource);
  983. this.setCachedFilteredSortedDataSource(sortedDataSource);
  984. this.setAllDisabledRowKeys(allDataDisabledRowKeys);
  985. const pageData = this.getCurrentPageData(sortedDataSource);
  986. this.setAdapterPageData(pageData);
  987. }
  988. getQuery(dataIndex: string, queries?: BaseColumnProps<RecordType>[]) {
  989. queries = queries || this.getState('queries');
  990. if (dataIndex != null) {
  991. return find(queries, query => query.dataIndex === dataIndex);
  992. }
  993. return undefined;
  994. }
  995. getCellWidths(flattenedColumns: BaseColumnProps<RecordType>[], flattenedWidths?: BaseHeadWidth[], ignoreScrollBarKey?: boolean) {
  996. return this._adapter.getCellWidths(flattenedColumns, flattenedWidths, ignoreScrollBarKey);
  997. }
  998. setHeadWidths(headWidths: Array<BaseHeadWidth>, index?: number) {
  999. return this._adapter.setHeadWidths(headWidths, index);
  1000. }
  1001. getHeadWidths(index: number) {
  1002. return this._adapter.getHeadWidths(index);
  1003. }
  1004. mergedRowExpandable(record: RecordType) {
  1005. return this._adapter.mergedRowExpandable(record);
  1006. }
  1007. setBodyHasScrollbar(bodyHasScrollbar: boolean) {
  1008. this._adapter.setBodyHasScrollbar(bodyHasScrollbar);
  1009. }
  1010. isSortOrderValid = (sortOrder: BaseSortOrder) => strings.SORT_DIRECTIONS.includes(sortOrder as any) || sortOrder === false;
  1011. }
  1012. export type BaseRowKeyType = string | number;
  1013. export interface BasePagination {
  1014. total?: number;
  1015. currentPage?: number;
  1016. pageSize?: number;
  1017. position?: ArrayElement<typeof strings.PAGINATION_POSITIONS>;
  1018. defaultCurrentPage?: number;
  1019. formatPageText?: any
  1020. }
  1021. export interface BaseHeadWidth {
  1022. width: number;
  1023. key: string
  1024. }
  1025. export interface BasePageData<RecordType> {
  1026. dataSource?: RecordType[];
  1027. groups?: Map<string, RecordType[]>;
  1028. pagination?: BasePagination;
  1029. disabledRowKeys?: BaseRowKeyType[];
  1030. allRowKeys?: BaseRowKeyType[];
  1031. queries?: BaseColumnProps<RecordType>[]
  1032. }
  1033. export type GetCheckboxProps<RecordType> = (record?: RecordType) => BaseCheckboxProps;
  1034. export type BaseGroupBy<RecordType> = string | number | BaseGroupByFn<RecordType>;
  1035. export type BaseGroupByFn<RecordType> = (record?: RecordType) => string | number;
  1036. export interface BaseSorterInfo<RecordType> {
  1037. [x: string]: any;
  1038. dataIndex?: string;
  1039. sortOrder?: BaseSortOrder;
  1040. sorter?: BaseSorter<RecordType>
  1041. }
  1042. export type BaseSortOrder = boolean | ArrayElement<typeof strings.SORT_DIRECTIONS>;
  1043. export type BaseSorter<RecordType> = boolean | ((a?: RecordType, b?: RecordType) => number);
  1044. export interface BaseChangeInfoFilter<RecordType> {
  1045. dataIndex?: string;
  1046. value?: any;
  1047. text?: any;
  1048. filters?: BaseFilter[];
  1049. onFilter?: (filteredValue?: any, record?: RecordType) => boolean;
  1050. filteredValue?: any[];
  1051. defaultFilteredValue?: any[];
  1052. children?: BaseFilter[];
  1053. filterChildrenRecord?: boolean
  1054. }
  1055. export interface BaseFilter {
  1056. value?: any;
  1057. text?: any;
  1058. children?: BaseFilter[]
  1059. }
  1060. export type BaseFixed = ArrayElement<typeof strings.FIXED_SET>;
  1061. export type BaseAlign = ArrayElement<typeof strings.ALIGNS>;
  1062. export type BaseOnCell<RecordType> = (record?: RecordType, rowIndex?: number) => BaseOnCellReturnObject;
  1063. export interface BaseOnCellReturnObject {
  1064. [x: string]: any;
  1065. style?: Record<string, any>;
  1066. className?: string;
  1067. onClick?: (e: any) => void
  1068. }
  1069. export type BaseOnFilter<RecordType> = (filteredValue?: any, record?: RecordType) => boolean;
  1070. export type BaseOnFilterDropdownVisibleChange = (visible?: boolean) => void;
  1071. export type BaseOnHeaderCell<RecordType> = (record?: RecordType, columnIndex?: number) => BaseOnHeaderCellReturnObject;
  1072. export interface BaseOnHeaderCellReturnObject {
  1073. [x: string]: any;
  1074. style?: Record<string, any>;
  1075. className?: string;
  1076. onClick?: (e: any) => void
  1077. }
  1078. export interface BaseChangeInfoSorter<RecordType> {
  1079. [x: string]: any;
  1080. dataIndex: string;
  1081. sortOrder: BaseSortOrder;
  1082. sorter: BaseSorter<RecordType>
  1083. }
  1084. export type BaseIncludeGroupRecord<RecordType> = RecordType | { groupKey: string };
  1085. export default TableFoundation;