@bit-sun/business-component 2.4.31-alpha.9 → 2.4.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/index.d.ts +0 -1
  2. package/dist/index.esm.js +823 -862
  3. package/dist/index.js +822 -864
  4. package/dist/utils/auth.d.ts +0 -1
  5. package/dist/utils/utils.d.ts +1 -1
  6. package/package.json +5 -8
  7. package/src/components/Business/AddSelectBusiness/index.md +0 -236
  8. package/src/components/Business/AddSelectBusiness/index.tsx +296 -333
  9. package/src/components/Business/BsLayouts/Components/GlobalHeader/index.tsx +1 -0
  10. package/src/components/Business/BsLayouts/index.tsx +23 -111
  11. package/src/components/Business/BsLayouts/utils.tsx +0 -2
  12. package/src/components/Business/BsSulaQueryTable/index.tsx +90 -44
  13. package/src/components/Business/CommodityEntry/index.md +1 -15
  14. package/src/components/Business/CommodityEntry/index.tsx +0 -1
  15. package/src/components/Business/DetailPageWrapper/index.tsx +1 -2
  16. package/src/components/Business/SearchSelect/index.md +1 -10
  17. package/src/components/Functional/AddSelect/helps.ts +1 -1
  18. package/src/components/Functional/AddSelect/index.tsx +223 -63
  19. package/src/components/Functional/DataImport/index.tsx +30 -35
  20. package/src/components/Functional/DataValidation/index.md +2 -15
  21. package/src/components/Functional/DataValidation/index.tsx +26 -39
  22. package/src/components/Functional/SearchSelect/index.tsx +1 -1
  23. package/src/index.ts +0 -1
  24. package/src/utils/auth.ts +1 -7
  25. package/dist/components/Functional/AccessWrapper/index.d.ts +0 -5
  26. package/dist/components/Functional/AuthButton/index.d.ts +0 -3
  27. package/src/components/Functional/AccessWrapper/index.tsx +0 -34
  28. package/src/components/Functional/AuthButton/index.tsx +0 -15
@@ -45,8 +45,6 @@ import { HTML5Backend } from 'react-dnd-html5-backend';
45
45
  import ENUM from '@/utils/enumConfig';
46
46
  import { memoizeOneFormatter } from '@/utils/utils';
47
47
  import Item from 'antd/lib/list/Item';
48
- import { getLimitMenuDataKey, shouldUseAuth } from '@/utils';
49
- import NoFoundPage from '@/components/Functional/AccessWrapper';
50
48
 
51
49
  const { TabPane } = Tabs;
52
50
 
@@ -64,43 +62,6 @@ export type BasicLayoutContext = { [K in 'location']: BasicLayoutProps[K] } & {
64
62
  breadcrumbNameMap: Record<string, MenuDataItem>;
65
63
  };
66
64
 
67
- const getId = (str) => {
68
- // 找到最后一个 / 的位置
69
- var lastSlashIndex = str.lastIndexOf("/");
70
-
71
- // 如果找到了 /,则返回它后面的部分
72
- if (lastSlashIndex !== -1) {
73
- return str.substring(lastSlashIndex + 1);
74
- } else {
75
- // 如果没有找到 /,则返回整个字符串
76
- return null;
77
- }
78
- }
79
-
80
- // 获取权限菜单path&通用单据id
81
- const getAuthMenuPathAndDocsId = (pathToRegexp) => {
82
- const limitedMenuData = localStorage.getItem(getLimitMenuDataKey()) ? JSON.parse(localStorage.getItem(getLimitMenuDataKey())) : [];
83
- const menuKeys = [];
84
- const docsId = [];
85
- const getLimitedMenuKeys = (data) => {
86
- data.forEach((item) => {
87
- if (item.children && item.children.length > 0) {
88
- getLimitedMenuKeys(item.children);
89
- } else {
90
- const originPath = item.path.replace(/^\/\w+\//, '/');
91
- menuKeys.push(originPath);
92
- if (pathToRegexp('/operation-and-maintenance-center/configuration-management/all-general-documents-specific/:id').test(originPath)) {
93
- getId(originPath) && docsId.push(getId(originPath))
94
- }
95
- }
96
- });
97
- };
98
- try {
99
- getLimitedMenuKeys(limitedMenuData);
100
- } catch(e) {}
101
- return {menuKeys, docsId};
102
- }
103
-
104
65
  const menuDataRender = (menuList: MenuDataItem[]): MenuDataItem[] =>
105
66
  menuList.map((item) => {
106
67
  return {
@@ -111,8 +72,6 @@ const menuDataRender = (menuList: MenuDataItem[]): MenuDataItem[] =>
111
72
 
112
73
  let UN_LISTTEN_DRP;
113
74
  let routerArray = [];
114
- let authMenuPathList = [];
115
- let docsId = [];
116
75
  let lastTwoRouterArray = [1, 2];
117
76
 
118
77
  let draggerTabKeys = [];
@@ -328,9 +287,7 @@ class BasicLayout extends React.PureComponent {
328
287
  }>();
329
288
  constructor(props) {
330
289
  super(props);
331
- authMenuPathList = getAuthMenuPathAndDocsId(props.pathToRegexp)?.menuKeys || [];
332
- docsId = getAuthMenuPathAndDocsId(props.pathToRegexp)?.docsId || [];
333
- routerArray = this.updateTree(props.route.routes, authMenuPathList);
290
+ routerArray = this.updateTree(props.route.routes);
334
291
  const homeRouter = routerArray.filter(
335
292
  (itemroute) => itemroute.key === '/',
336
293
  )[0];
@@ -434,27 +391,9 @@ class BasicLayout extends React.PureComponent {
434
391
  let newListenRouterState = [...listenRouterState];
435
392
  let newListenRouterKey = [...listenRouterKey];
436
393
 
437
- /**
438
- * 根据给定的路由数组和当前路由信息,筛选出与当前路由匹配的路由项。
439
- *
440
- * @param routerArray 路由数组,包含多个路由项,每个路由项有一个键(key)。
441
- * @param route 当前的路由信息,包含路径(pathname)等信息。
442
- * @param docsId 通用单据ID的数组,用于进一步筛选路由。
443
- * @returns 返回与当前路由匹配的第一个路由项,如果没有匹配项则返回undefined。
444
- */
445
- let replaceRouter = routerArray.filter((itemRoute) => {
446
- // 单独处理通用单据预览
447
- if (window.top !== window && !window.__POWERED_BY_WUJIE__ && route.pathname?.includes('all-general-documents')) {
448
- return pathToRegexp(itemRoute.key || '').test(route.pathname);
449
- }
450
- // 当路由路径包含'all-general-documents'时,按通用单据处理
451
- if (route.pathname?.includes('all-general-documents') && shouldUseAuth()) {
452
- // 检查路由路径是否匹配路由项的键,并且路径中包含至少一个通用单据ID
453
- return pathToRegexp(itemRoute.key || '').test(route.pathname) && docsId.some(item => route.pathname.includes(item));
454
- }
455
- // 对于不包含'all-general-documents'的路径,只检查路由路径是否匹配路由项的键
456
- return pathToRegexp(itemRoute.key || '').test(route.pathname);
457
- })[0];
394
+ let replaceRouter = routerArray.filter((itemRoute) =>
395
+ pathToRegexp(itemRoute.key || '').test(route.pathname),
396
+ )[0];
458
397
 
459
398
  let currentKey = '';
460
399
 
@@ -481,23 +420,24 @@ class BasicLayout extends React.PureComponent {
481
420
  }
482
421
 
483
422
  if (!listenRouterKey.includes(currentKey)) {
484
-
485
423
  if (!replaceRouter) {
486
- replaceRouter = {
487
- content: currentKey,
488
- key: currentKey,
489
- name:'404',
490
- tab: '404',
491
- isNotFound: true,
492
- }
424
+ replaceRouter = routerArray.filter(
425
+ (itemroute) => itemroute.key === '/404',
426
+ )?.[0];
493
427
 
494
- newListenRouterState = [
495
- ...newListenRouterState,
428
+ this.setState(
496
429
  {
497
- ...replaceRouter,
430
+ listenRouterState: [
431
+ ...listenRouterState,
432
+ { ...replaceRouter, key: currentKey, tab: '404' },
433
+ ],
434
+ activeKey: currentKey,
435
+ listenRouterKey: [...listenRouterKey, currentKey],
498
436
  },
499
- ];
500
- newListenRouterKey = [...listenRouterKey, currentKey];
437
+ () => {
438
+ this.checkisNavSlide();
439
+ },
440
+ );
501
441
  } else {
502
442
  const match = matchPath(route.pathname, { path: replaceRouter.key }, pathToRegexp);
503
443
  newListenRouterState = [
@@ -600,44 +540,15 @@ class BasicLayout extends React.PureComponent {
600
540
  return queryString;
601
541
  };
602
542
 
603
- updateTree = (Tree, authMenuKeys = []) => {
543
+ updateTree = (Tree) => {
604
544
  const treeData = Tree;
605
545
  const treeList = [];
606
-
607
-
608
-
609
- // 是否为权限菜单路径
610
- const getLimitedMenuPath = (node) => {
611
- return authMenuKeys.some(item => (node.path || '').includes(item));
612
- }
613
-
614
- // 是否为通用单据菜单路径
615
- const getGenerateDocs = (node) => {
616
- return (node.path || '').includes('all-general-documents');
617
- }
618
-
619
546
  // 递归获取树列表
620
547
  const getTreeList = (data) => {
621
548
  data.forEach((node) => {
622
549
  if (node.routes && node.routes.length > 0) {
623
550
  getTreeList(node.routes);
624
- return;
625
- }
626
- // todo:暂时处理非wujie环境不做404管控
627
- if (!window.__POWERED_BY_WUJIE__) {
628
- treeList.push({
629
- tab: node.locale,
630
- key: node.path,
631
- locale: node.locale,
632
- closable: true,
633
- content: node.component,
634
- name: node.name,
635
- hideInMenu: node.hideInMenu,
636
- isOnlyOnePage: node.isOnlyOnePage,
637
- });
638
- return;
639
- }
640
- if (node.path === '/' || getLimitedMenuPath(node) || getGenerateDocs(node)) {
551
+ } else {
641
552
  treeList.push({
642
553
  tab: node.locale,
643
554
  key: node.path,
@@ -725,6 +636,7 @@ class BasicLayout extends React.PureComponent {
725
636
  };
726
637
 
727
638
  onChange = (key) => {
639
+ // console.log('onChange');
728
640
  if (key !== this.state.activeKey) {
729
641
  this.setState({
730
642
  activeKey: key,
@@ -1540,10 +1452,10 @@ class WrapperComponent extends React.Component {
1540
1452
  timeFormat,
1541
1453
  transparentProps,
1542
1454
  } = this.props;
1455
+ console.log('child wrapper conpent', this.props)
1543
1456
  return (
1544
1457
  <>
1545
- {item.isNotFound ? ( <NoFoundPage />) :
1546
- React.createElement(item.content, {
1458
+ {React.createElement(item.content, {
1547
1459
  getDictionarySource: getDictionarySource,
1548
1460
  getDictionaryTextByValue: getDictionaryTextByValue,
1549
1461
  timeFormat: timeFormat,
@@ -3,7 +3,6 @@ import cloneDeep from 'lodash/cloneDeep';
3
3
  import memoizeOne from 'memoize-one';
4
4
  import { getMenuAuthDataKey } from '@/utils/LocalstorageUtils'
5
5
  import { history } from 'umi';
6
- import { shouldUseAuth } from '@/utils';
7
6
 
8
7
  const cache = {};
9
8
  const cacheLimit = 10000;
@@ -123,7 +122,6 @@ export const setMenuTreeData = (routesData: Array<any>) => {
123
122
  continue;
124
123
  }
125
124
  if (
126
- shouldUseAuth() &&
127
125
  routesData[i].code &&
128
126
  authButton.every((item) => {
129
127
  return routesData[i].code != item;
@@ -20,7 +20,20 @@ import ExportIcon from '@/components/Functional/ExportFunctions/ExportIcon';
20
20
  import ENUM from '@/utils/enumConfig';
21
21
  import { handleBssulaColumnsSpecialParams } from '@/utils/utils';
22
22
  import { getMenuAuthDataKey } from '@/utils/LocalstorageUtils';
23
- import { shouldUseAuth } from '@/utils';
23
+
24
+ interface Field {
25
+ name: string;
26
+ label: string;
27
+ field: any;
28
+ }
29
+
30
+ interface Column {
31
+ key?: string | string[];
32
+ dataIndex?: string | string[];
33
+ notRegularCheckList?: boolean;
34
+ width?: number | string;
35
+ onHeaderCell?: (column: Column) => any; // 仅作示例,具体类型根据实际情况定义
36
+ }
24
37
 
25
38
  const MemoQueryTable = React.memo(QueryTable);
26
39
 
@@ -44,6 +57,20 @@ const ResizeableTitle = (props) => {
44
57
 
45
58
  export default (props: any) => {
46
59
  const bsTableCode = props?.tableCode || window.location.hash; //设置列字段的唯一标识
60
+
61
+ // 获取 table columns中所有的 key 防止有的地方是 dataindex
62
+ const checkedList = useMemo(
63
+ () =>
64
+ props.columns
65
+ .filter((col: any) => !col.hidden)
66
+ .map((d: any) =>
67
+ Array.isArray(d.key || d.dataIndex)
68
+ ? JSON.stringify(d.key || d.dataIndex)
69
+ : d.key || d.dataIndex,
70
+ ),
71
+ [props.columns],
72
+ );
73
+
47
74
  const getConfigFromlocalstorage = (type: string) => {
48
75
  let config = localStorage.getItem(type) || '[]';
49
76
  let configArray = JSON.parse(config);
@@ -56,32 +83,68 @@ export default (props: any) => {
56
83
  }
57
84
  return [];
58
85
  };
59
- const getInitialSearchFieldsInfo = () =>{
60
- //获取搜索字段的缓存配置
61
- const { fields = [] } = props;
62
- let searchFieldsConfig = getConfigFromlocalstorage(ENUM.BROWSER_CACHE.SEARCH_FIELDS_CONDITION);
63
- let showSearchFields = searchFieldsConfig.length ? searchFieldsConfig.map((item) => {
64
- let inner = fields.filter(
65
- (inneritem) => {
66
- let innerKey = Array.isArray(inneritem.name) ? JSON.stringify(inneritem.name) : inneritem.name;
67
- let itemKey = Array.isArray(item.name) ? JSON.stringify(item.name) : item.name;
68
- return innerKey && innerKey === itemKey;
69
- }
70
- )[0];
71
86
 
72
- return {
73
- ...inner,
74
- ...item,
75
- };
76
- }) : fields;
77
- return [...showSearchFields]
87
+ /**
88
+ * 根据保存的配置和原始配置,获取设置的字段或列。
89
+ * @param savedConfig 保存的配置数组,可能包含字段或列的配置。
90
+ * @param originConfig 原始配置数组,包含完整的字段或列信息。
91
+ * @param type 字段或列的类型,用于确定配置的属性。
92
+ * @returns 返回根据保存的配置处理后的字段或列数组,如果未保存任何配置,则返回原始配置。
93
+ */
94
+ const getSettingFieldOrColumn = (savedConfig, originConfig, type: string) => {
95
+ /**
96
+ * 判断值是否为字符串数组。
97
+ * @param value 待判断的值。
98
+ * @returns 如果值是字符串数组,则返回true,否则返回false。
99
+ */
100
+ const isStringArray = (value: any): value is string[] => {
101
+ return Array.isArray(value) && value.every(v => typeof v === 'string');
78
102
  }
103
+
104
+ /**
105
+ * 根据配置项和类型,获取配置项的键。
106
+ * @param config 配置项,可以是字段或列。
107
+ * @param type 配置项的类型。
108
+ * @returns 返回配置项的键,如果无法获取,则返回空字符串。
109
+ */
110
+ const getItemKey = (config: Column | Field, type: string): string => {
111
+ try {
112
+ if (type === 'columns') {
113
+ return isStringArray(config.key) ? JSON.stringify(config.key) : isStringArray(config.dataIndex) ? JSON.stringify(config.dataIndex) : config.key || config.dataIndex || '';
114
+ }
115
+ return isStringArray(config.name) ? JSON.stringify(config.name) : config.name || '';
116
+ } catch(e) {}
117
+ return '';
118
+ }
119
+
120
+ const newConfig = [];
121
+
122
+ if (savedConfig.length) {
123
+ const hash = originConfig.reduce((prev, inneritem) => {
124
+ prev[getItemKey(inneritem, type)] = inneritem;
125
+ return prev;
126
+ }, {} as { [key: string]: Column | Field });
127
+
128
+ savedConfig.forEach((config, index) => {
129
+ let inner = hash[getItemKey(config, type)];
130
+ inner && newConfig.push({ ...inner, ...config });
131
+ })
132
+ }
133
+
134
+ if (newConfig.length) return newConfig;
135
+
136
+ if (type === 'columns') {
137
+ return originConfig.filter(column => {
138
+ const columnKey = getItemKey(column, type);
139
+ return column.notRegularCheckList || checkedList.indexOf(columnKey) > -1;
140
+ });
141
+ }
142
+
143
+ return [...originConfig];
144
+ }
145
+
79
146
  const refs = useRef(null);
80
147
  const [pagePath, setPagePath] = useState('');
81
- // 获取 table columns中所有的 key 防止有的地方是 dataindex
82
- const [checkedList, setCheckedList] = useState(
83
- props.columns.filter((col: any) => !col.hidden).map((d: any) => Array.isArray(d.key || d.dataIndex) ? JSON.stringify(d.key || d.dataIndex) : (d.key || d.dataIndex)),
84
- );
85
148
  const { pathname } = useLocation();
86
149
  const [id]: any = useState(
87
150
  Number(Math.random().toString().substr(2, 0) + Date.now()).toString(36),
@@ -89,8 +152,9 @@ export default (props: any) => {
89
152
  const [isFullScreen, setIsFnllScreen]: any = useState(false);
90
153
  // @ts-nocheck
91
154
  const [value, setValue]: any = useState(props);
155
+ const { fields = [] } = props;
92
156
  const [showColumn, setShowColumns] = useState([]); // 列字段
93
- const originSearchFields = getInitialSearchFieldsInfo();
157
+ const originSearchFields = getSettingFieldOrColumn(getConfigFromlocalstorage(ENUM.BROWSER_CACHE.SEARCH_FIELDS_CONDITION), fields, 'searchFields');
94
158
  const [showSearchFields, setShowSearchFields] = useState(originSearchFields); //搜索项字段
95
159
  const { isPage = true, pagination, tableCode, appRequestConfig } = props;
96
160
 
@@ -178,7 +242,7 @@ export default (props: any) => {
178
242
  if (Number(item.slice(-1)) >= 1) {
179
243
  Item = item.substr(0, item.length - 1);
180
244
  }
181
- if (shouldUseAuth() && !authButton.filter((itemInner: any) => Item === itemInner).length) {
245
+ if (!authButton.filter((itemInner: any) => Item === itemInner).length) {
182
246
  resourceCodeArray[item].visible = false;
183
247
  }
184
248
  });
@@ -190,25 +254,7 @@ export default (props: any) => {
190
254
  });
191
255
  const { columns } = props;
192
256
  let columnConfig = getConfigFromlocalstorage(ENUM.BROWSER_CACHE.COLUMN_CONDITION);
193
- let showColumns = columnConfig.length ? columnConfig.map((item) => {
194
- let inner = columns.filter(
195
- (inneritem) => {
196
- let innerKey = Array.isArray(inneritem.key || inneritem.dataIndex) ? JSON.stringify(inneritem.key || inneritem.dataIndex) : (inneritem.key || inneritem.dataIndex);
197
- let itemKey = Array.isArray(item.key || item.dataIndex) ? JSON.stringify(item.key || item.dataIndex) : (item.key || item.dataIndex);
198
- return innerKey && innerKey === itemKey;
199
- }
200
- )[0];
201
-
202
- return {
203
- ...inner,
204
- ...item,
205
- };
206
- }) : columns.filter(
207
- (column) => {
208
- let columnKey = Array.isArray(column.key || column.dataIndex) ? JSON.stringify(column.key || column.dataIndex) : (column.key || column.dataIndex);
209
- return column.notRegularCheckList || checkedList.indexOf(columnKey) > -1;
210
- }
211
- )
257
+ let showColumns = getSettingFieldOrColumn(columnConfig, columns, 'columns');
212
258
 
213
259
  showColumns.forEach((item, index) => {
214
260
  item.width = item.width || getItemDefaultWidth(item);
@@ -54,21 +54,7 @@ export default () => {
54
54
  const props = {
55
55
  callbackHideModal,
56
56
  callbackHandleOk,
57
- isCheckStockNum: false, // 默认为true,校验库存数量,false,则不校验库存
58
- customerColumnsMapping: [
59
- {
60
- title: 'SKU编码',
61
- name: 'skuCode'
62
- },
63
- {
64
- title: '批号',
65
- name: 'lotNumberCode'
66
- },
67
- {
68
- title: '数量',
69
- name: 'quantity'
70
- }
71
- ] // 自定义展示列
57
+ isCheckStockNum: false // 默认为true,校验库存数量,false,则不校验库存
72
58
  }
73
59
 
74
60
  return (
@@ -66,7 +66,6 @@ const CommodityEntry = (props: any) => {
66
66
  {modalProps.visible && (
67
67
  <Modal {...modalProps} onOk={handleOk} onCancel={handleCancel} destroyOnClose={true} zIndex={15} {...otherModalProps} >
68
68
  <DataValidation
69
- {...props}
70
69
  onRef={(ref) => { dataValidationRef = ref }}
71
70
  columns={columns}
72
71
  validDataUrl={validDataUrl}
@@ -17,7 +17,6 @@ import moreIcon from '../../../assets/btn-more.svg';
17
17
  import { useLocation, formatMessage } from 'umi';
18
18
  import CommonAlert from '../CommonAlert';
19
19
  import { getMenuAuthDataKey, getLimitMenuDataKey } from '@/utils/LocalstorageUtils';
20
- import { shouldUseAuth } from '@/utils';
21
20
 
22
21
  interface actionItem {
23
22
  type?: string;
@@ -155,7 +154,7 @@ const DetailWrapper = React.memo(
155
154
  let visibleActions = actionLists.filter(
156
155
  (action) =>
157
156
  ((action.visible && action.visible !== 'false') || judgeIsEmpty(action.visible)) &&
158
- (!shouldUseAuth() || (judgeIsEmpty(action.code) || authButton.filter(item => item === action.code))),
157
+ (judgeIsEmpty(action.code) || authButton.filter(item => item === action.code)),
159
158
  );
160
159
 
161
160
  const renderButton = (item: actionItem, type?: any) => {
@@ -102,7 +102,7 @@ export default () => {
102
102
 
103
103
  ```tsx
104
104
  import React, { useState } from 'react';
105
- import { Tabs, Button } from 'antd';
105
+ import { Tabs } from 'antd';
106
106
  import {BusinessSearchSelect} from '../../../index.ts';
107
107
 
108
108
  const { TabPane } = Tabs;
@@ -121,10 +121,6 @@ export default () => {
121
121
  modalRadioNeedFooter: true
122
122
  }
123
123
 
124
- const fieldComponentProps = {
125
- fieldComponent: <Button type='primary'>添加</Button>
126
- }
127
-
128
124
  const [ tabKey, setTabKey ] = useState('single')
129
125
  const [value, setValue] = useState(selectProps?.mode ? [] : null);
130
126
 
@@ -165,11 +161,6 @@ export default () => {
165
161
  {tabKey === 'singleConfirm' && (
166
162
  <BusinessSearchSelect {...props} modalTableProps={singleConfirmModalTableProps} />
167
163
  )}
168
- </TabPane>
169
- <TabPane tab='点击按钮弹窗' key='buttonModal'>
170
- {tabKey === 'buttonModal' && (
171
- <BusinessSearchSelect {...props} {...fieldComponentProps} selectProps={selectPropsMultiple} />
172
- )}
173
164
  </TabPane>
174
165
  <TabPane tab='多选' key='multiple'>
175
166
  {tabKey === 'multiple' && (
@@ -10,7 +10,7 @@ import { judgeIsRequestError } from '@/utils/requestUtils';
10
10
  export const getSelectDataList = (record: any,item: any, selectKey: string) => {
11
11
  let result = [];
12
12
  if(item?.dataSourceCode) {
13
- result = record?.[item?.dataSourceCode] || []
13
+ result = record?.[item?.dataSourceCode]
14
14
  }
15
15
  if(item?.dataSource?.length) {
16
16
  result = item?.filterDataSourceCode ? item.dataSource.filter((i: any) => record[item?.filterDataSourceCode]?.some((s: any) => s == i[selectKey])) : item.dataSource