@hzab/form-render 1.6.11 → 1.6.12

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ # @hzab/form-render@1.6.12
2
+
3
+ feat: PersonnelSelect组件优化传值方式,支持复数据传入、返回
4
+
1
5
  # @hzab/form-render@1.6.11
2
6
 
3
7
  feat: editor添加配置merage
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hzab/form-render",
3
- "version": "1.6.11",
3
+ "version": "1.6.12",
4
4
  "description": "",
5
5
  "main": "src",
6
6
  "scripts": {
@@ -1,8 +1,8 @@
1
1
  import React, { useEffect, useState, useRef, useCallback, useMemo } from "react";
2
2
  import { Select, List, Avatar, Spin } from "antd";
3
3
  import { connect, mapProps } from "@formily/react";
4
- import { debounce, isObject } from "lodash";
5
- import type { LableValue, Person, ScrollPagination, RemoteSelectProps } from "./type";
4
+ import { debounce, isObject, isPlainObject } from "lodash";
5
+ import type { LabelValue, ScrollPagination, RemoteSelectProps } from "./type";
6
6
 
7
7
  import "./index.less";
8
8
 
@@ -14,7 +14,7 @@ const defaultListItemConfigs = [
14
14
  { label: "身份证号:", key: "idnumber" },
15
15
  ];
16
16
 
17
- const transfromLabelInValueData = (list: Person[], labelKey: string, valueKey: string): Person[] => {
17
+ const transfromLabelInValueData = (list: LabelValue[], labelKey: string, valueKey: string): LabelValue[] => {
18
18
  try {
19
19
  return list.map((item) => ({ ...item, label: item?.[labelKey], value: item?.[valueKey] }));
20
20
  } catch (e) {
@@ -24,7 +24,8 @@ const transfromLabelInValueData = (list: Person[], labelKey: string, valueKey: s
24
24
  };
25
25
 
26
26
  const RemoteSelect: React.FC<RemoteSelectProps> = ({
27
- loadOptions,
27
+ loadData,
28
+ searchData,
28
29
  renderItem,
29
30
  listItemConfigs,
30
31
  labelKey = "userName",
@@ -34,12 +35,15 @@ const RemoteSelect: React.FC<RemoteSelectProps> = ({
34
35
  avataProps = {},
35
36
  disabledStyle,
36
37
  customItemNode,
38
+ labelInValue = false,
39
+ isClearable = false,
37
40
  ...selectProps
38
41
  }) => {
39
42
  const [search, setSearch] = useState("");
40
43
  const [loading, setLoading] = useState(false);
41
44
  const [loadingMore, setLoadingMore] = useState(false);
42
- const [list, setList] = useState<Person[]>([]);
45
+ const [list, setList] = useState<LabelValue[]>([]);
46
+ const [cacheDeafultList, setCacheDeafultList] = useState<LabelValue[]>([]);
43
47
  const [pagination, setPagination] = useState<ScrollPagination>({
44
48
  pageNum: 1,
45
49
  pageSize: 10,
@@ -47,12 +51,13 @@ const RemoteSelect: React.FC<RemoteSelectProps> = ({
47
51
  });
48
52
  const selectInstance = useRef<any>(null);
49
53
  const total = useRef(0);
54
+ const initSearch = useRef(true);
50
55
 
51
56
  const debounceLoadData = debounce(async (isScrollLoad = false) => {
52
57
  try {
53
58
  isScrollLoad ? setLoadingMore(true) : setLoading(true);
54
59
 
55
- const result = await loadOptions(search, {
60
+ const result = await loadData(search, {
56
61
  ...pagination,
57
62
  pageNum: isScrollLoad ? pagination.pageNum + 1 : 1,
58
63
  });
@@ -60,7 +65,7 @@ const RemoteSelect: React.FC<RemoteSelectProps> = ({
60
65
 
61
66
  total.current = resPagination.total;
62
67
 
63
- const transformatList: Person[] = transfromLabelInValueData(list, labelKey, valueKey);
68
+ const transformatList: LabelValue[] = transfromLabelInValueData(list, labelKey, valueKey);
64
69
 
65
70
  setList((prev) => (isScrollLoad ? [...prev, ...transformatList] : transformatList));
66
71
  } finally {
@@ -73,15 +78,15 @@ const RemoteSelect: React.FC<RemoteSelectProps> = ({
73
78
  const isNearBottom = scrollHeight - scrollTop - clientHeight < 30;
74
79
 
75
80
  if (isNearBottom && !loadingMore && list.length <= total.current) {
76
- await loadData(true);
81
+ await getData(true);
77
82
  setPagination((pre) => ({ ...pre, pageNum: pagination.pageNum + 1 }));
78
83
  }
79
84
  };
80
85
 
81
- const loadData = useCallback(debounceLoadData, [search, pagination, loadOptions]);
86
+ const getData = useCallback(debounceLoadData, [search, pagination, loadData]);
82
87
 
83
88
  // 处理滚动加载
84
- const handleScroll = useCallback(debounceHandleScroll, [loadingMore, loadData]);
89
+ const handleScroll = useCallback(debounceHandleScroll, [search, loadingMore, loadData]);
85
90
 
86
91
  // 重置list滚动条
87
92
  const resetListScroll = () => {
@@ -96,36 +101,61 @@ const RemoteSelect: React.FC<RemoteSelectProps> = ({
96
101
  setPagination((prev) => ({ ...prev, pageNum: 1 }));
97
102
  }, 1000);
98
103
 
99
- useEffect(() => {
100
- loadData();
101
- }, [search]);
104
+ const handleOnDropdownVisibleChange = (open: boolean) => {
105
+ if (!isClearable) return;
106
+ if (open) {
107
+ getData();
108
+ } else {
109
+ resetListScroll();
110
+ setList([]);
111
+ setPagination((prev) => ({ ...prev, pageNum: 1 }));
112
+ }
113
+ };
102
114
 
103
115
  // 处理选项点击事件
104
- const handleItemClick = (item: Person) => {
116
+ const handleItemClick = (item: LabelValue) => {
105
117
  const { value: currentValue, mode, onChange } = selectProps;
106
- const itemId = item.userId;
118
+ const itemId = item.value;
107
119
 
108
120
  // 多选模式处理
109
121
  const handleMultipleSelection = () => {
110
- const selectedOptions = Array.isArray(currentValue) ? currentValue : [];
111
- const isSelected = selectedOptions.some((opt) => opt.value === itemId);
122
+ const selectedOptions: any[] = Array.isArray(currentValue) ? currentValue : [currentValue];
123
+
124
+ if (labelInValue) {
125
+ const isSelected = selectedOptions.some((opt) => opt.value === itemId);
126
+
127
+ return isSelected
128
+ ? selectedOptions.filter((opt) => opt.value !== itemId) // 移除已选项
129
+ : [...selectedOptions, item]; // 添加新选项
130
+ }
131
+
132
+ const isSelected = selectedOptions.some((opt) => opt === itemId);
112
133
 
113
134
  return isSelected
114
- ? selectedOptions.filter((opt) => opt.value !== itemId) // 移除已选项
135
+ ? selectedOptions.filter((opt) => opt !== itemId) // 移除已选项
115
136
  : [...selectedOptions, item]; // 添加新选项
116
137
  };
117
138
 
118
139
  // 单选模式处理
119
140
  const handleSingleSelection = () => {
120
- const isCurrentSelected = (currentValue as LableValue)?.value === itemId;
141
+ const isCurrentSelected = (currentValue as LabelValue)?.value === itemId;
121
142
  return isCurrentSelected ? undefined : item;
122
143
  };
123
144
 
145
+ let resultValue: string | number | any[] | LabelValue;
146
+
124
147
  // 执行模式对应处理
125
148
  const newValue = mode === "multiple" ? handleMultipleSelection() : handleSingleSelection();
126
149
 
150
+ if (mode === "multiple") {
151
+ if (labelInValue) resultValue = newValue;
152
+ else resultValue = newValue.map((x: LabelValue | string | number) => (typeof x === "object" ? x?.value : x));
153
+ } else {
154
+ labelInValue ? (resultValue = newValue) : (resultValue = (newValue as unknown as LabelValue).value);
155
+ }
156
+
127
157
  // 触发变更回调
128
- onChange?.(newValue, currentValue);
158
+ onChange?.(resultValue, currentValue as any);
129
159
 
130
160
  // 单选模式自动关闭下拉框
131
161
  if (mode !== "multiple" && selectInstance.current) selectInstance.current.blur();
@@ -137,19 +167,39 @@ const RemoteSelect: React.FC<RemoteSelectProps> = ({
137
167
  return defaultListItemConfigs;
138
168
  }, [listItemConfigs]);
139
169
 
170
+ useEffect(() => {
171
+ getData();
172
+ }, [search]);
173
+ useEffect(() => {
174
+ // 当value为一个id或者id数组时,需要进行数据查询用以回显label等信息
175
+ if (!labelInValue && selectProps.value && typeof searchData === "function" && initSearch.current) {
176
+ searchData?.(selectProps.value).then((res: Record<string, any>) => {
177
+ setCacheDeafultList(res?.list || []);
178
+ setList(res?.list || []);
179
+ });
180
+ // 只有初始化时执行
181
+ initSearch.current = false;
182
+ }
183
+ }, [selectProps.value]);
184
+
140
185
  // 默认渲染项(增加选中状态和点击处理)
141
186
  const defaultRenderItem = useCallback(
142
- (item: Person) => {
187
+ (item: LabelValue) => {
143
188
  const { mode, value: selectedValue } = selectProps;
144
- const { userId, [disabledKey]: isDisabled = false } = item;
189
+ const { value, [disabledKey]: isDisabled = false } = item;
145
190
  // 选中状态判断
146
191
  const getSelectionStatus = () => {
147
192
  if (mode === "multiple") {
148
193
  if (!Array.isArray(selectedValue)) return false;
149
- const selectedValues = (selectedValue || [])?.map((opt) => (isObject(opt) ? opt?.value ?? opt?.userId : opt));
150
- return selectedValues.includes(userId);
194
+ const selectedValues = (selectedValue || [])?.map((opt) => (isObject(opt) ? opt?.value ?? opt?.value : opt));
195
+ return selectedValues.includes(value);
196
+ }
197
+
198
+ if (Array.isArray(cacheDeafultList)) {
199
+ return cacheDeafultList.map((x) => x.value).includes(value);
151
200
  }
152
- return isObject(selectedValue) ? (selectedValue as LableValue)?.value === userId : false;
201
+
202
+ return isObject(selectedValue) ? (selectedValue as LabelValue)?.value === value : selectedValue === value;
153
203
  };
154
204
 
155
205
  // 禁用样式生成
@@ -182,9 +232,9 @@ const RemoteSelect: React.FC<RemoteSelectProps> = ({
182
232
  );
183
233
 
184
234
  return (
185
- <List.Item key={userId} onClick={() => !isDisabled && handleItemClick(item)} style={generateStyle(isDisabled)}>
235
+ <List.Item key={value} onClick={() => !isDisabled && handleItemClick(item)} style={generateStyle(isDisabled)}>
186
236
  {customItemNode || (
187
- <div className="abt-user-item">
237
+ <div className="abt-user-item" key={item?.value}>
188
238
  <div className="abt-user-item-avatar">{avatarComponent}</div>
189
239
  {userInfoContent}
190
240
  </div>
@@ -192,7 +242,7 @@ const RemoteSelect: React.FC<RemoteSelectProps> = ({
192
242
  </List.Item>
193
243
  );
194
244
  },
195
- [selectProps.value],
245
+ [selectProps.value, list?.length],
196
246
  );
197
247
 
198
248
  // 自定义下拉内容
@@ -216,8 +266,8 @@ const RemoteSelect: React.FC<RemoteSelectProps> = ({
216
266
  <Select
217
267
  {...selectProps}
218
268
  ref={selectInstance}
269
+ onDropdownVisibleChange={handleOnDropdownVisibleChange}
219
270
  showSearch
220
- labelInValue
221
271
  onSearch={handleSearch}
222
272
  filterOption={false}
223
273
  dropdownRender={dropdownRender}
@@ -2,41 +2,40 @@ import type { SelectProps } from "antd/lib/select";
2
2
  import React from "react";
3
3
  import type { AvatarProps } from "antd/lib/avatar";
4
4
 
5
- export interface Person {
6
- userId: string | number;
7
- userName: string;
8
- avatar?: string;
9
- email?: string;
10
- description?: string;
11
- disabled?: boolean;
12
- [key: string]: any;
13
- }
14
-
15
5
  export interface ScrollPagination {
16
6
  pageNum: number;
17
7
  pageSize: number;
18
8
  current?: number;
9
+ hasMore?: boolean;
19
10
  total?: number;
20
11
  }
21
12
 
22
- export type LableValue = {
13
+ export type LabelValue = {
23
14
  label: string;
24
15
  value: string | number;
25
16
  [key: string]: any;
26
17
  };
27
18
 
28
- export interface RemoteSelectProps extends Omit<SelectProps<any>, "options" | "children"> {
19
+ interface BaseSelectProps extends Omit<SelectProps<any>, "options" | "children"> {
29
20
  /**
30
21
  * @title 请求函数
31
22
  * */
32
- loadOptions: (
23
+ loadData: (
33
24
  search: string,
34
25
  pagination: ScrollPagination,
35
- ) => Promise<{ list: Person[]; pagination: ScrollPagination }>;
26
+ ) => Promise<{ list: LabelValue[]; pagination: ScrollPagination }>;
27
+ /**
28
+ * @title 查询函数
29
+ * */
30
+ searchData?: <T = Record<string, any>, U = any[]>(query: T) => Promise<U[]>;
36
31
  /**
37
32
  * @title 自定义列表项
38
33
  * */
39
- renderItem?: (item: Person) => React.ReactNode;
34
+ renderItem?: (item: LabelValue) => React.ReactNode;
35
+ /**
36
+ * @title 下拉框收起时是否清除数据
37
+ * */
38
+ isClearable?: boolean;
40
39
  /**
41
40
  * @title 分页参数
42
41
  * */
@@ -45,10 +44,7 @@ export interface RemoteSelectProps extends Omit<SelectProps<any>, "options" | "c
45
44
  * @title antd头像组件props
46
45
  * */
47
46
  avataProps?: AvatarProps;
48
- /**
49
- * @title 下拉框值
50
- * */
51
- value: LableValue[] | LableValue;
47
+ mode: "multiple" | "tags";
52
48
  /**
53
49
  * @title 列表项内部展示的字段内容
54
50
  * */
@@ -74,3 +70,23 @@ export interface RemoteSelectProps extends Omit<SelectProps<any>, "options" | "c
74
70
  * */
75
71
  customItemNode?: React.ReactNode;
76
72
  }
73
+
74
+ // 多选模式
75
+ export interface RemoteSelectMultipleProps extends BaseSelectProps {
76
+ mode: "multiple";
77
+ /**
78
+ * @title 下拉框值
79
+ * */
80
+ value?: LabelValue[] | Array<string | number>;
81
+ }
82
+
83
+ // 单选模式
84
+ export interface RemoteSelectTagsProps extends BaseSelectProps {
85
+ mode: "tags";
86
+ /**
87
+ * @title 下拉框值
88
+ * */
89
+ value?: LabelValue | string | number;
90
+ }
91
+
92
+ export type RemoteSelectProps = RemoteSelectMultipleProps | RemoteSelectTagsProps;