@bit-sun/business-component 4.2.1-alpha.7-longya → 4.2.1-alpha.8

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 (27) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/dist/components/Functional/SearchSelect/pagination.d.ts +3 -3
  3. package/dist/index.esm.js +416 -953
  4. package/dist/index.js +415 -952
  5. package/docs/error-record.md +0 -9
  6. package/package.json +1 -1
  7. package/src/components/Business/AddSelectBusiness/index.tsx +8 -124
  8. package/src/components/Business/SearchSelect/BusinessUtils.tsx +12 -106
  9. package/src/components/Business/columnSettingTable/sulaSettingTable.tsx +1 -1
  10. package/src/components/Functional/AddSelect/helps.ts +0 -2
  11. package/src/components/Functional/AddSelect/index.less +0 -17
  12. package/src/components/Functional/AddSelect/index.tsx +9 -66
  13. package/src/components/Functional/SearchSelect/index.less +0 -16
  14. package/src/components/Functional/SearchSelect/index.md +2 -0
  15. package/src/components/Functional/SearchSelect/index.tsx +65 -77
  16. package/src/components/Functional/SearchSelect/pagination.ts +4 -4
  17. package/src/components/Solution/RuleComponent/ruleFiled.js +155 -176
  18. package/dist/components/Functional/QueryAutoComplete/buildOptions.d.ts +0 -3
  19. package/dist/components/Functional/QueryAutoComplete/buildOptions.test.d.ts +0 -1
  20. package/dist/components/Functional/QueryAutoComplete/index.d.ts +0 -23
  21. package/dist/components/Functional/SearchSelect/currentPageFilter.d.ts +0 -41
  22. package/docs/superpowers/plans/2026-10-12-IKJX29-sku-name-autocomplete.md +0 -489
  23. package/docs/superpowers/specs/2026-10-12-IKJX29-sku-name-autocomplete-design.md +0 -115
  24. package/src/components/Functional/QueryAutoComplete/buildOptions.test.ts +0 -22
  25. package/src/components/Functional/QueryAutoComplete/buildOptions.ts +0 -17
  26. package/src/components/Functional/QueryAutoComplete/index.tsx +0 -140
  27. package/src/components/Functional/SearchSelect/currentPageFilter.ts +0 -135
@@ -1,5 +1,5 @@
1
1
  // @ts-nocheck
2
- import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
2
+ import React, { useState, useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
3
3
  import { useDebounceFn } from 'ahooks';
4
4
  import { Input, Button, Modal, Select, Divider, message, Spin, Form, Table, Checkbox, TreeSelect, Tooltip, Tag, Row, Col, Space, Tabs, Empty, DatePicker } from 'antd';
5
5
  import { SearchOutlined, CopyOutlined, CaretLeftOutlined } from '@ant-design/icons';
@@ -19,8 +19,6 @@ import { judgeIsRequestError } from '@/utils/requestUtils';
19
19
  import zhankaitiaojian from '../../../assets/zhankaitiaojian-icon.svg';
20
20
  import PropertySelector from '@/components/Business/PropertyModal';
21
21
  import ItemPropertySelector from '@/components/Business/ItemPropertySelector';
22
- import { buildCurrentPageFilterColumns, markCurrentPageFilterByDataIndex } from './currentPageFilter';
23
- import QueryAutoComplete from '../QueryAutoComplete';
24
22
 
25
23
  const { Option } = Select;
26
24
 
@@ -55,6 +53,7 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
55
53
  mappingTextField = 'name',
56
54
  mappingTextShowKeyField,
57
55
  mappingValueField = 'code',
56
+ mappingOutputField,
58
57
  mappingTextShowTextField,
59
58
  init = false,// 是否初始请求,默认初始不请求,查询需要限制录入4位数以上支持模糊查询
60
59
  extralHeaders = {},// 额外请求头参数
@@ -66,7 +65,7 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
66
65
  isQuery = false, // 是否是查询条件
67
66
  requestType = 'get', // 自定义弹窗时候的查询方式 如果是post 并且需要所有参数都放在body里 需要设置此参数 && 兼容之前逻辑
68
67
  } = rCTemp || {};
69
- const requestConfig = {url,method,otherParams,isMap,fixedparameter,fieldValToParam,fixedparamsDisabled,mappingTextField,mappingTextShowKeyField,mappingValueField,mappingTextShowTextField,init,extralHeaders,specialBracket,noNeedSplit,noOperate,viewShowValueStr,searchStartLength,...rCTemp};
68
+ const requestConfig = {url,method,otherParams,isMap,fixedparameter,fieldValToParam,fixedparamsDisabled,mappingTextField,mappingTextShowKeyField,mappingValueField,mappingOutputField,mappingTextShowTextField,init,extralHeaders,specialBracket,noNeedSplit,noOperate,viewShowValueStr,searchStartLength,...rCTemp};
70
69
  const resultSourceKey = handleSourceName(sourceName || requestConfig?.sourceName || ctx?.name || 'supplierCode')
71
70
 
72
71
  const selectMode = selectProps?.mode // 设定当前选择器 为单选或者多选模式 无设定为单选模式(默认)
@@ -109,6 +108,30 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
109
108
  const sDisabled = disabled || (isHaveDependency && !!!isHaveDValue() && !isQuery);
110
109
 
111
110
  const [items, setItems] = useState([]);
111
+ const selectedRecordsRef = useRef<any[]>([]);
112
+ const [, refreshSelectedRecords] = useState(0);
113
+
114
+ /**
115
+ * 使用记录标识维护选中状态,同时保留原有表单业务值。
116
+ */
117
+ const getSelectedRecords = () => {
118
+ if (!mappingOutputField || !value) return [];
119
+ const outputValues = selectMode ? value : [value];
120
+ const codes = new Set((Array.isArray(outputValues) ? outputValues : [outputValues]).map((item: any) => labelInValue ? item?.value ?? item?.key : item));
121
+ return [...codes].flatMap((code: any) => {
122
+ const cached = selectedRecordsRef.current.filter((item: any) => item[mappingOutputField] === code);
123
+ return cached.length ? cached : items.filter((item: any) => item[mappingOutputField] === code).slice(0, 1);
124
+ });
125
+ };
126
+
127
+ const getIdentityValue = () => {
128
+ if (!mappingOutputField) return value;
129
+ const keys = getSelectedRecords().map((item: any) => labelInValue
130
+ ? { key: item[mappingValueField], value: item[mappingValueField], label: item[mappingTextField] }
131
+ : item[mappingValueField]);
132
+ if (!keys.length) return value;
133
+ return selectMode ? keys : keys[0];
134
+ };
112
135
  const [selectOpen, setSelectOpen] = useState(false);
113
136
  const [isMaxTagsOpen, setIsMaxTagsOpen] = useState(false);
114
137
  const [scrollPage, setScrollPage] = useState(1);
@@ -156,7 +179,6 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
156
179
  const [tableFormParams, setTableFormParams] = useState({});
157
180
  const [tooltipVisible, setTooltipVisible] = useState(false);
158
181
  const [tableShowColumns, setTabletShowColumns] = useState(handleTableColumns(modalTableProps?.tableColumns)); // 默认展示表头-modalTableProps?.tableColumns
159
- const [currentPageFilters, setCurrentPageFilters] = useState({});
160
182
  const [confirmLoading, setConfirmLoading] = useState(false);
161
183
  const [modalSearched, setModalSearched]=useState(false);
162
184
 
@@ -277,7 +299,7 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
277
299
  return;
278
300
  }
279
301
  const res = result.data;
280
- const source: any = convertResData(requestConfig, res, { selectMode, labelInValue, value, type, items, queryParams, needTopSelectedSource });
302
+ const source: any = convertResData(requestConfig, res, { selectMode, labelInValue, value: getIdentityValue(), type, items, queryParams, needTopSelectedSource });
281
303
 
282
304
  if(callback) {
283
305
  callback(source)
@@ -286,7 +308,6 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
286
308
  ctx?.form?.setFieldSource(resultSourceKey, source)
287
309
  setSelectDataSource(source,(Number(res?.total || res?.totalCount || source.length)))
288
310
  } else {
289
- setCurrentPageFilters({});
290
311
  setTableData(source)
291
312
  setTablePagination({ ...tablePagination, total: Number(res?.total || res?.totalCount || source.length), pageSize: Number(res?.size || res?.pageSize || (params?.pageSize || pageSize)), current: Number(res?.page || res?.currentPage || (params?.currentPage || currentPage)) })
292
313
  }
@@ -418,6 +439,15 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
418
439
  setTablePagination({ ...tableInitPagination, pageSize: cachedPageSize, current: 1 });
419
440
 
420
441
  setIsModalVisible(true);
442
+ if (mappingOutputField) {
443
+ const records = getSelectedRecords();
444
+ setSelectedRowKeys(records.map((item: any) => item[mappingValueField]));
445
+ setSelectedRows(records);
446
+ setPopValue(records);
447
+ setIndeterminate(!!records.length && records.length < itemsTotal);
448
+ setCheckedAll(!!itemsTotal && records.length === itemsTotal);
449
+ return;
450
+ }
421
451
  // 回显
422
452
  if (value) {
423
453
  if (selectMode) {
@@ -498,13 +528,17 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
498
528
  };
499
529
 
500
530
  const formaData = (value: any, source: any) => {
531
+ if (mappingOutputField) {
532
+ selectedRecordsRef.current = value;
533
+ refreshSelectedRecords((current: number) => current + 1);
534
+ }
501
535
  if (labelInValue) {
502
536
  const getFromat = (format, val) => format.map(({key,value})=> ({[key]:val[value]}))
503
- const formatResult = value.map((i: any) => (Object.assign({ key: i[mappingValueField] || i.key, label: i[mappingTextField] || i.label, value: i[mappingValueField] || i.value }, ...getFromat(returnFormat, i))))
504
- onChange(selectMode ? formatResult : formatResult[0], value,source)
537
+ const formatResult = value.map((i: any) => (Object.assign({ key: i[mappingOutputField || mappingValueField] || i.key, label: i[mappingTextField] || i.label, value: i[mappingOutputField || mappingValueField] || i.value }, ...getFromat(returnFormat, i))))
538
+ onChange(selectMode ? mappingOutputField ? _.uniqBy(formatResult, 'value') : formatResult : formatResult[0], value,source)
505
539
  } else {
506
- const formatResult = selectMode ? value.map((i: any) => i.value) : _.get(value[0], 'value')
507
- onChange(formatResult, value,source)
540
+ const formatResult = selectMode ? value.map((i: any) => mappingOutputField ? i[mappingOutputField] : i.value) : mappingOutputField ? value[0]?.[mappingOutputField] : _.get(value[0], 'value')
541
+ onChange(selectMode && mappingOutputField ? _.uniq(formatResult) : formatResult, value,source)
508
542
  }
509
543
  };
510
544
 
@@ -512,7 +546,6 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
512
546
  form.resetFields();
513
547
  setTableFormParams({});
514
548
  setTableData([]);
515
- setCurrentPageFilters({});
516
549
  setTablePagination(tableInitPagination);
517
550
  setSelectedRowKeys([]);
518
551
  setSelectedRows([]);
@@ -549,7 +582,6 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
549
582
  const pageSize = normalizeSearchSelectModalPageSize(tablePagination?.pageSize);
550
583
  setModalSearched(true);
551
584
  setTableFormParams(params);
552
- setCurrentPageFilters({});
553
585
  getData({ ...params, pageSize, currentPage: 1 }, 2, null);
554
586
  }
555
587
 
@@ -557,7 +589,6 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
557
589
  const pageSize = normalizeSearchSelectModalPageSize(tablePagination?.pageSize);
558
590
  form.resetFields();
559
591
  setTableFormParams({});
560
- setCurrentPageFilters({});
561
592
  getData({ pageSize, currentPage: 1 }, 2)
562
593
  }
563
594
 
@@ -565,15 +596,9 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
565
596
  setCollapsed(!collapsed);
566
597
  };
567
598
 
568
- const handleTableChange = (pagination, filters, sorter, extra) => {
569
- if (extra?.action === 'filter') {
570
- setCurrentPageFilters(filters || {});
571
- return;
572
- }
573
-
599
+ const handleTableChange = (pagination) => {
574
600
  const pageSize = normalizeSearchSelectModalPageSize(pagination.pageSize);
575
601
  setSearchSelectModalPageSize(pageSize);
576
- setCurrentPageFilters({});
577
602
  getData({ ...tableFormParams, pageSize, currentPage: pagination.current }, 2)
578
603
  }
579
604
 
@@ -729,19 +754,6 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
729
754
  </Col>
730
755
  );
731
756
  }
732
- if (i?.type === 'autoComplete' || i?.field?.type === 'autoComplete') {
733
- return (
734
- <Col span={ColSpan} key={i.name}>
735
- <Form.Item name={i.name} label={i.label} key={i.name}>
736
- <QueryAutoComplete
737
- onPressEnter={onSearchTable}
738
- disabled={setDisabled(i.name)}
739
- {...(i?.field?.props || {})}
740
- />
741
- </Form.Item>
742
- </Col>
743
- );
744
- }
745
757
  if (i?.field?.type === 'proppertySelector') {
746
758
  return (
747
759
  <Col span={ColSpan} key={i.name}>
@@ -806,47 +818,14 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
806
818
  const x = tableList?.length ? 82 : 28; // 无数据没有分页,有数据计算减去:分页 24+16*2+10 「高 + margin * 2 + paddingBottom 10 」
807
819
  const oSY = `calc(100vh - ${tableBoxHeighth}px - ${x}px)`;
808
820
  const mTB = `calc(50vh - ${tableBoxHeighth/2}px - ${x/2}px - 40px)`
809
- const currentColumns = buildCurrentPageFilterColumns(
810
- markCurrentPageFilterByDataIndex(tableShowColumns),
811
- tableList,
812
- currentPageFilters,
813
- type !== 'noPage',
814
- );
815
- // 无 width 的列在固定 scroll.x 下会被挤没;先兜底宽度再按列宽求和
816
- const DEFAULT_COLUMN_WIDTH = 120;
817
- const columnsWithWidth = currentColumns.map((col: any) => {
818
- if (typeof col?.width === 'number' && col.width > 0) {
819
- return col;
820
- }
821
- if (typeof col?.width === 'string') {
822
- const parsed = parseFloat(col.width);
823
- if (Number.isFinite(parsed) && parsed > 0) {
824
- return { ...col, width: parsed };
825
- }
826
- }
827
- return { ...col, width: DEFAULT_COLUMN_WIDTH };
828
- });
829
- const sumColumnScrollX = (columns: any[], extraWidth = 0) => {
830
- const sum = (columns || []).reduce(
831
- (total: number, col: any) => total + (Number(col?.width) || DEFAULT_COLUMN_WIDTH),
832
- extraWidth,
833
- );
834
- return sum > extraWidth ? sum : undefined;
835
- };
836
- const tableScrollX = modalTableProps.overScrollX
837
- || sumColumnScrollX(columnsWithWidth, rowSelection ? 60 : 0)
838
- || true;
839
821
  return (
840
822
  <div style={{ height: `calc(100vh - ${tableBoxHeighth}px)` }}>
841
823
  <Table
842
824
  bordered
843
825
  size="middle"
844
826
  rowSelection={rowSelection}
845
- columns={columnsWithWidth}
827
+ columns={tableShowColumns}
846
828
  dataSource={tableList}
847
- getPopupContainer={(triggerNode) =>
848
- modalTableProps?.getFilterPopupContainer?.(triggerNode) || document.body
849
- }
850
829
  {...type=='noPage'?{
851
830
  pagination: { ...initPagination,showSizeChanger: false },
852
831
  locale: {
@@ -862,7 +841,7 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
862
841
  }}
863
842
  rowKey={mappingValueField}
864
843
  scroll={{
865
- x: tableScrollX,
844
+ x: modalTableProps.overScrollX || 'max-content',
866
845
  y: modalTableProps.overScrollY || oSY,
867
846
  }}
868
847
  onRow={(record) => {
@@ -903,7 +882,7 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
903
882
  }
904
883
 
905
884
  const onDeselect = (...arg) => {
906
- const oldSelect = formatSelectedValue(value);
885
+ const oldSelect = mappingOutputField ? getSelectedRecords() : formatSelectedValue(value);
907
886
  const deRecord = arg[1];
908
887
  const srs = oldSelect.filter((s: any) => s.value != deRecord?.value)
909
888
  onSelectClick(srs, items,false)
@@ -927,7 +906,7 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
927
906
  }
928
907
  }
929
908
  const renderTable = (dataSource) => {
930
- const currentSRKs = getCurrentSRKs(selectMode,labelInValue,value)
909
+ const currentSRKs = getCurrentSRKs(selectMode,labelInValue,getIdentityValue())
931
910
  const renderSource = getRenderSource(currentSRKs,items)
932
911
 
933
912
  return (
@@ -942,7 +921,7 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
942
921
  selectedRowKeys: currentSRKs,
943
922
  preserveSelectedRowKeys: true, // 避免搜索之后 没有了选中前的数据 保证sks的正确性
944
923
  onChange: (sks, srs) => {
945
- const oldSelect = formatSelectedValue(value);
924
+ const oldSelect = mappingOutputField ? getSelectedRecords() : formatSelectedValue(value);
946
925
  let tmpSelectedRows = oldSelect.concat(srs).filter(item => item != undefined);
947
926
  let realSrs = sks.map(key => tmpSelectedRows.filter(item => item.value == key)[0]).filter(item => item != undefined)
948
927
  onSelectClick(realSrs, dataSource,false)
@@ -953,7 +932,7 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
953
932
  event.stopPropagation();
954
933
  event.nativeEvent.stopImmediatePropagation();
955
934
 
956
- const oldSelect = formatSelectedValue(value);
935
+ const oldSelect = mappingOutputField ? getSelectedRecords() : formatSelectedValue(value);
957
936
  const newSelect = [JSON.parse(JSON.stringify(record))];
958
937
  const srs = getRealStr(oldSelect,newSelect,record);
959
938
  onSelectClick(srs,dataSource,false)
@@ -983,6 +962,15 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
983
962
  );
984
963
  }
985
964
 
965
+ /**
966
+ * 折叠标签移除记录时,先按内部标识更新选中项,再回传业务值。
967
+ */
968
+ const onRemoveIdentityTag = (remainingValue: any) => {
969
+ const keys = getCurrentSRKs(selectMode, labelInValue, remainingValue);
970
+ const records = getSelectedRecords().filter((item: any) => keys.includes(item[mappingValueField]));
971
+ onSelectClick(records, items, false);
972
+ };
973
+
986
974
  const isShouldShowStr = (props.disabled && ctx) || ctx?.mode == 'view';
987
975
  return (
988
976
  <div className={'search_select'}>
@@ -997,8 +985,8 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
997
985
  </div>
998
986
  ) : (
999
987
  isShouldShowStr ?
1000
- (<div title={getShowStr({ viewShowValueStr, labelInValue, selectMode, value, items })} style={{overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}} className={'search_select_show'}>
1001
- {getShowStr({viewShowValueStr, labelInValue, selectMode, value, items })}
988
+ (<div title={getShowStr({ viewShowValueStr, labelInValue, selectMode, value: getIdentityValue(), items })} style={{overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}} className={'search_select_show'}>
989
+ {getShowStr({viewShowValueStr, labelInValue, selectMode, value: getIdentityValue(), items })}
1002
990
  </div>) :
1003
991
  <div
1004
992
  className={`${isFormPage ? '' : 'search_select_show_list'} search_select_show`}
@@ -1006,7 +994,7 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
1006
994
  >
1007
995
  <Select
1008
996
  labelInValue={labelInValue}
1009
- value={value}
997
+ value={getIdentityValue()}
1010
998
  onChange={onchange}
1011
999
  onClear={onClear}
1012
1000
  onDeselect={onDeselect}
@@ -1027,7 +1015,7 @@ const SearchSelect = forwardRef((props: any, ref: any) => {
1027
1015
  onPopupScroll={SelectScroll}
1028
1016
  style={{ width: 'calc(100%)' }}
1029
1017
  placeholder="请选择"
1030
- maxTagPlaceholder={(v)=> maxTagPlaceholder(v,{ selectProps:{labelInValue}, onChange, value, setIsMaxTagsOpen })}
1018
+ maxTagPlaceholder={(v)=> maxTagPlaceholder(v,{ selectProps:{labelInValue}, onChange: mappingOutputField ? onRemoveIdentityTag : onChange, value: getIdentityValue(), setIsMaxTagsOpen })}
1031
1019
  onSearch={(v) => onSearchChange(v)}
1032
1020
  {...(needModalTable ? {
1033
1021
  suffixIcon: <div className={`search_select_expand_button ${(sDisabled)?'search_select_expand_button_disabled':''}`} onClick={showModal}><SearchOutlined /></div>
@@ -1,11 +1,11 @@
1
- export const SEARCH_SELECT_MODAL_DEFAULT_PAGE_SIZE = 200;
1
+ export const SEARCH_SELECT_MODAL_DEFAULT_PAGE_SIZE = 100;
2
2
 
3
- export const SEARCH_SELECT_MODAL_PAGE_SIZE_OPTIONS = [10, 20, 50, 100, 200, 300, 500, 1000];
3
+ export const SEARCH_SELECT_MODAL_PAGE_SIZE_OPTIONS = [10, 20, 50, 100, 500, 1000];
4
4
 
5
5
  export const SEARCH_SELECT_MODAL_PAGE_SIZE_CACHE_KEY = 'businessComponentSearchSelectPageSize';
6
6
 
7
7
  /**
8
- * 规范化选择器弹窗分页大小,缓存异常时统一回退到默认条数。
8
+ * 规范化选择器弹窗分页大小,缓存异常时统一回退到每页 100 条。
9
9
  *
10
10
  * @param pageSize 待校验的分页大小
11
11
  * @returns 合法的分页大小
@@ -20,7 +20,7 @@ export const normalizeSearchSelectModalPageSize = (pageSize: unknown): number =>
20
20
  /**
21
21
  * 读取所有选择器弹窗共用的分页大小。
22
22
  *
23
- * @returns 缓存中的分页大小,无有效缓存时返回默认条数
23
+ * @returns 缓存中的分页大小,无有效缓存时返回每页 100 条
24
24
  */
25
25
  export const getSearchSelectModalPageSize = (): number => {
26
26
  if (typeof window === 'undefined') {