@hzab/form-render 1.6.11 → 1.6.13

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,11 @@
1
+ # @hzab/form-render@1.6.13
2
+
3
+ feat:locationListPicker在已有元素范围内可新增地址标记
4
+
5
+ # @hzab/form-render@1.6.12
6
+
7
+ feat: PersonnelSelect组件优化传值方式,支持复数据传入、返回
8
+
1
9
  # @hzab/form-render@1.6.11
2
10
 
3
11
  feat: editor添加配置merage
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@hzab/form-render",
3
- "version": "1.6.11",
3
+ "version": "1.6.13",
4
4
  "description": "",
5
5
  "main": "src",
6
6
  "scripts": {
7
7
  "dev": "webpack serve -c ./config/webpack.config.js --env local",
8
8
  "build": "webpack -c ./config/webpack.config.js --env production",
9
+ "publish-beta": "npm publish --beta",
9
10
  "publish-patch": "npm version patch && npm publish --access public",
10
11
  "publish-minor": "npm version minor && npm publish --access public",
11
12
  "publish-major": "npm version major && npm publish --access public"
@@ -89,7 +89,7 @@ export const LocationListPicker = observer((props) => {
89
89
  data: item,
90
90
  onClick: onMarkerClick,
91
91
  });
92
- mapUtilsRef.current.setCircle(item.longitude, item.latitude, item.range, { ...item });
92
+ mapUtilsRef.current.setCircle(item.longitude, item.latitude, item.range, { ...item, onClick: handleMarker });
93
93
  }
94
94
  });
95
95
  mapUtilsRef.current.setFitView();
@@ -199,8 +199,14 @@ export const LocationListPicker = observer((props) => {
199
199
  clearStatus();
200
200
  }
201
201
 
202
+
203
+ // 地图单击除现有元素范围外添加点位地址
204
+ function onMapClick(e) {
205
+ mapUtilsRef.current.isContains(e, handleMarker);
206
+ }
207
+
202
208
  // 处理 marker、范围 绘制填写逻辑
203
- async function onMapClick(e) {
209
+ async function handleMarker(e) {
204
210
  if (drawType.current !== "marker") {
205
211
  return;
206
212
  }
@@ -297,18 +303,20 @@ export const LocationListPicker = observer((props) => {
297
303
  }
298
304
 
299
305
  function onPolygonClick(e) {
300
- if (!isEditingRef.current) {
306
+ if (!isEditingRef.current && statusRef.current !== "add") {
301
307
  drawType.current = "polygon";
302
308
  const id = e.target.id;
303
309
  clearEdit(id);
304
310
  setActiveId(id);
305
311
  setActivePolygon(e.target);
312
+ } else if (statusRef.current === "add") {
313
+ handleMarker(e);
306
314
  }
307
315
  }
308
316
 
309
317
  function onMarkerClick(e, ...args) {
310
318
  clearActive();
311
- if (!isEditingRef.current) {
319
+ if (!isEditingRef.current && statusRef.current !== "add") {
312
320
  setShowTip(false);
313
321
  isEditingRef.current = false;
314
322
  const { id } = e.target.getExtData() || {};
@@ -412,7 +420,7 @@ export const LocationListPicker = observer((props) => {
412
420
  } else {
413
421
  setTipText("点击选择地址");
414
422
  setActiveMarkerIcon(item.id);
415
- onMapClick({
423
+ handleMarker({
416
424
  lnglat: {
417
425
  lng: item.longitude,
418
426
  lat: item.latitude,
@@ -458,7 +466,7 @@ export const LocationListPicker = observer((props) => {
458
466
  function setPoint(lng, lat) {
459
467
  mapUtilsRef.current.setCenter(lng, lat, { immediately: true });
460
468
  statusRef.current = "add";
461
- onMapClick({
469
+ handleMarker({
462
470
  lnglat: {
463
471
  lng,
464
472
  lat,
@@ -59,7 +59,7 @@ export class MapUtils {
59
59
  PolygonEditor: undefined,
60
60
  PolylineEditor: undefined,
61
61
  };
62
- public polygonEnum;
62
+ public polygonEnum = {};
63
63
  public polygonConf;
64
64
  public mapDomRef;
65
65
 
@@ -332,7 +332,7 @@ export class MapUtils {
332
332
  }
333
333
 
334
334
  setCircle(lon, lat, radius, opt?) {
335
- const { id = nanoid(), circle, map = this.map, AMap = this.AMap, circleConf = {} } = opt || {};
335
+ const { id = nanoid(), circle, map = this.map, AMap = this.AMap, onClick, circleConf = {} } = opt || {};
336
336
  if (!(AMap && map)) {
337
337
  throw new Error("请传入地图实例和 AMap");
338
338
  }
@@ -362,9 +362,10 @@ export class MapUtils {
362
362
  strokeWeight: 1, // 轮廓线宽度
363
363
  fillOpacity: 0.1, // 圆形填充透明度
364
364
  fillColor: "#0080FF", // 圆形填充颜色
365
- zIndex: 50, // 圆形的叠加顺序
365
+ zIndex: 100, // 圆形的叠加顺序
366
366
  ...circleConf,
367
367
  });
368
+ _c.on("click", onClick);
368
369
  this.circles[id] = _c;
369
370
  map?.add(_c);
370
371
  return _c;
@@ -375,6 +376,22 @@ export class MapUtils {
375
376
  delete this.circles[id];
376
377
  }
377
378
 
379
+
380
+ // 判断当前点击点位是否在地图现有元素范围内,并回调函数返回值
381
+ isContains(e, callBack) {
382
+ const element = {
383
+ ...this.circles,
384
+ ...this.polygonEnum,
385
+ };
386
+ const { lng, lat } = e.lnglat || {};
387
+ const point = new this.AMap.LngLat(lng, lat);
388
+ const isRange = Object.keys(element).some((key) => element[key].contains(point));
389
+ if (!isRange) {
390
+ callBack && callBack(e);
391
+ }
392
+ return isRange;
393
+ }
394
+
378
395
  /**
379
396
  * 创建或修改地图选点的 Marker
380
397
  * 在当前 utils 中唯一
@@ -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;