@hzab/form-render 1.6.16 → 1.6.18
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 +287 -280
- package/package.json +1 -1
- package/src/components/PersonnelSelect/index.tsx +305 -300
- package/src/components/Upload/common/fileName.ts +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,280 +1,287 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
-
|
|
205
|
-
|
|
206
|
-
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
- fix
|
|
235
|
-
- fix
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
1
|
+
# @hzab/form-render@1.6.18
|
|
2
|
+
|
|
3
|
+
fix:修复人员选择组件单选模式自定义节点展示以及选中判断问题
|
|
4
|
+
|
|
5
|
+
# @hzab/form-render@1.6.17
|
|
6
|
+
|
|
7
|
+
fix: 修复上传组件,文件名和后缀名取值逻辑
|
|
8
|
+
|
|
9
|
+
# @hzab/form-render@1.6.16
|
|
10
|
+
|
|
11
|
+
fix: ArrayTable value 空问题兼容
|
|
12
|
+
fix: 修复人员选择组件中 isObject 函数 ts 类型不明确导致在部分项目中出现类型错误提示的问题
|
|
13
|
+
|
|
14
|
+
# @hzab/form-render@1.6.15
|
|
15
|
+
|
|
16
|
+
feat: 新增 formily js 的 change 事件
|
|
17
|
+
|
|
18
|
+
# @hzab/form-render@1.6.14
|
|
19
|
+
|
|
20
|
+
fix: 修复 TreeCheckbox 隐藏不能点击问题。
|
|
21
|
+
|
|
22
|
+
# @hzab/form-render@1.6.13
|
|
23
|
+
|
|
24
|
+
feat:locationListPicker 在已有元素范围内可新增地址标记
|
|
25
|
+
|
|
26
|
+
# @hzab/form-render@1.6.12
|
|
27
|
+
|
|
28
|
+
feat: PersonnelSelect 组件优化传值方式,支持复数据传入、返回
|
|
29
|
+
|
|
30
|
+
# @hzab/form-render@1.6.11
|
|
31
|
+
|
|
32
|
+
feat: editor 添加配置 merage
|
|
33
|
+
|
|
34
|
+
# @hzab/form-render@1.6.10
|
|
35
|
+
|
|
36
|
+
feat: 富文本编辑器实例像外暴露
|
|
37
|
+
|
|
38
|
+
# @hzab/form-render@1.6.9
|
|
39
|
+
|
|
40
|
+
feat: PersonnelSelect 组件
|
|
41
|
+
|
|
42
|
+
# @hzab/form-render@1.6.8
|
|
43
|
+
|
|
44
|
+
feat:富文本组件添加私有化部署文件上传与 oss 上传的区分
|
|
45
|
+
|
|
46
|
+
# @hzab/form-render@1.6.7
|
|
47
|
+
|
|
48
|
+
fix: 修复 LocationListPicker 组件在编辑时第一次无法正确渲染的 bug。
|
|
49
|
+
|
|
50
|
+
# @hzab/form-render@1.6.5
|
|
51
|
+
|
|
52
|
+
fix: 修复 LocationListPicker 组件在编辑时第一次无法正确渲染的 bug。
|
|
53
|
+
feat: LocationPicker 渲染时增加范围
|
|
54
|
+
|
|
55
|
+
# @hzab/form-render@1.6.3
|
|
56
|
+
|
|
57
|
+
fix: 修复 LocationListPicker 组件的 Pupup 弹窗在某些时候漂移的 bug。
|
|
58
|
+
|
|
59
|
+
# @hzab/form-render@1.6.2
|
|
60
|
+
|
|
61
|
+
feat:自增列表组件新增删除二次确认功能
|
|
62
|
+
|
|
63
|
+
# @hzab/form-render@1.6.1
|
|
64
|
+
|
|
65
|
+
fix:列表新增-上传组件删除后清除对应的值
|
|
66
|
+
|
|
67
|
+
# @hzab/form-render@1.6.0
|
|
68
|
+
|
|
69
|
+
feat: 私有部署文件上传
|
|
70
|
+
fix: 文件名称是否 hash 支持配置 useHashName
|
|
71
|
+
|
|
72
|
+
# @hzab/form-render@1.5.1
|
|
73
|
+
|
|
74
|
+
fix: schemaScope 使用 Ref 缓存,解决 onChange tempData 更新问题
|
|
75
|
+
|
|
76
|
+
# @hzab/form-render@1.5.0
|
|
77
|
+
|
|
78
|
+
feat: ossUpload 文件目录配置 dir 前缀 oss-upload 文件目录;dir 格式格式化
|
|
79
|
+
feat: 上传组件多模式上传,出参格式配置
|
|
80
|
+
fix: 字符串事件处理(onChange)
|
|
81
|
+
|
|
82
|
+
# @hzab/form-render@1.4.1
|
|
83
|
+
|
|
84
|
+
fix: Upload 修复历史遗留问题,解决 单项上传始终解析为 对象/字符串 无法切换会数组的情况
|
|
85
|
+
|
|
86
|
+
# @hzab/form-render@1.4.0
|
|
87
|
+
|
|
88
|
+
break: location-list-picker 添加多区域规划
|
|
89
|
+
fix: LocationListPicker 点位信息弹窗位置问题修复
|
|
90
|
+
|
|
91
|
+
# @hzab/form-render@1.3.3
|
|
92
|
+
|
|
93
|
+
fix: 富文本异步数据问题修复
|
|
94
|
+
|
|
95
|
+
# @hzab/form-render@1.3.2
|
|
96
|
+
|
|
97
|
+
fix: schema props 为 schemaScope 字符串的情况
|
|
98
|
+
|
|
99
|
+
# @hzab/form-render@1.3.1
|
|
100
|
+
|
|
101
|
+
feat: 表单 onChange 事件(目前仅做触发,值计算后续优化)
|
|
102
|
+
|
|
103
|
+
# @hzab/form-render@1.3.0
|
|
104
|
+
|
|
105
|
+
break: 去除 lib,默认 src
|
|
106
|
+
|
|
107
|
+
# @hzab/form-render@1.2.5
|
|
108
|
+
|
|
109
|
+
- fix: LocationListPicker 组件高度调整与删除点位修复
|
|
110
|
+
|
|
111
|
+
# @hzab/form-render@1.2.4
|
|
112
|
+
|
|
113
|
+
fix: ossUpload 入参问题修复
|
|
114
|
+
fix: UserSelect InfoRender
|
|
115
|
+
|
|
116
|
+
# @hzab/form-render@1.2.3
|
|
117
|
+
|
|
118
|
+
- fix: 富文本添加 loading 样式
|
|
119
|
+
|
|
120
|
+
# @hzab/form-render@1.2.2
|
|
121
|
+
|
|
122
|
+
- fix: Upload 预览 src(修复版)
|
|
123
|
+
|
|
124
|
+
# @hzab/form-render@1.2.1
|
|
125
|
+
|
|
126
|
+
- fix: 富文本 video 样式调整
|
|
127
|
+
|
|
128
|
+
# @hzab/form-render@1.2.0
|
|
129
|
+
|
|
130
|
+
- feat: Upload 增加 video 视频上传配置
|
|
131
|
+
|
|
132
|
+
# @hzab/form-render@1.1.7
|
|
133
|
+
|
|
134
|
+
- fix: Upload 预览 src
|
|
135
|
+
|
|
136
|
+
# @hzab/form-render@1.1.6
|
|
137
|
+
|
|
138
|
+
fix: 时间范围修复
|
|
139
|
+
|
|
140
|
+
# @hzab/form-render@1.1.5
|
|
141
|
+
|
|
142
|
+
fix: Upload 预览优化
|
|
143
|
+
|
|
144
|
+
# @hzab/form-render@1.1.4
|
|
145
|
+
|
|
146
|
+
fix: Upload 添加内部地址拼接
|
|
147
|
+
|
|
148
|
+
# @hzab/form-render@1.1.3
|
|
149
|
+
|
|
150
|
+
fix: Upload 添加预览配置
|
|
151
|
+
|
|
152
|
+
# @hzab/form-render@1.1.2
|
|
153
|
+
|
|
154
|
+
- feat: LocationListPicker 优化;列表激活状态、新增按钮提示、marker 激活状态及相关交互
|
|
155
|
+
|
|
156
|
+
# @hzab/form-render@1.1.1
|
|
157
|
+
|
|
158
|
+
- Upload OSS 上传支持数组对象格式值
|
|
159
|
+
|
|
160
|
+
# @hzab/form-render@1.1.0
|
|
161
|
+
|
|
162
|
+
- feat: LocationListPicker 组件
|
|
163
|
+
|
|
164
|
+
# @hzab/form-render@1.0.3
|
|
165
|
+
|
|
166
|
+
- fix: dayjs 自定义解析器,解决 YYYY 年 MM 月 DD 日 格式问题
|
|
167
|
+
|
|
168
|
+
# @hzab/form-render@1.0.2
|
|
169
|
+
|
|
170
|
+
- fix: Upload 预览文件判断逻辑
|
|
171
|
+
|
|
172
|
+
# @hzab/form-render@1.0.1
|
|
173
|
+
|
|
174
|
+
- fix: 提交结果为字符串处理 isOssUpload || isStrRes
|
|
175
|
+
|
|
176
|
+
# @hzab/form-render@1.0.0
|
|
177
|
+
|
|
178
|
+
- feat: @formily/antd 使用 c-formily-antd 替换,formily 相关包升级至 2.3.1 "@formily/core": "^2.3.1", "@formily/react": "^2.3.1", "c-formily-antd": "^2.3.1",
|
|
179
|
+
|
|
180
|
+
# @hzab/form-render@0.7.4
|
|
181
|
+
|
|
182
|
+
- RichEditor zIndex
|
|
183
|
+
|
|
184
|
+
# @hzab/form-render@0.7.3
|
|
185
|
+
|
|
186
|
+
- fix: Upload 通过 accept 判断文件类型
|
|
187
|
+
|
|
188
|
+
# @hzab/form-render@0.7.2
|
|
189
|
+
|
|
190
|
+
- fix: ossUpload axios 数据结构兼容
|
|
191
|
+
|
|
192
|
+
# @hzab/form-render@0.7.1
|
|
193
|
+
|
|
194
|
+
- Upload props customRequest
|
|
195
|
+
|
|
196
|
+
# @hzab/form-render@0.7.0
|
|
197
|
+
|
|
198
|
+
- 富文本组件 RichEditor
|
|
199
|
+
|
|
200
|
+
# @hzab/form-render@0.6.2
|
|
201
|
+
|
|
202
|
+
- fix: TreeCheckbox tabs 强制渲染,解决 checkbox 没有渲染导致值丢失的问题
|
|
203
|
+
|
|
204
|
+
# @hzab/form-render@0.6.1
|
|
205
|
+
|
|
206
|
+
- fix: LocationPicker MapSearch 只读模式选择结果只修改地图中心点
|
|
207
|
+
- fix: LocationPicker 解决 AMap 异步加载导致 setPickPoint 异常的问题
|
|
208
|
+
|
|
209
|
+
# @hzab/form-render@0.6.0
|
|
210
|
+
|
|
211
|
+
- feat: TreeCheckbox 支持无线层 tab
|
|
212
|
+
- feat: TreeCheckbox 支持合并叶子节点
|
|
213
|
+
- refactor: svg-icon.js -> svg-icon.jsx
|
|
214
|
+
|
|
215
|
+
# @hzab/form-render@0.5.5
|
|
216
|
+
|
|
217
|
+
- fix: TreeCheckbox key 问题修复
|
|
218
|
+
- fix: TreeCheckbox 数据兼容处理
|
|
219
|
+
|
|
220
|
+
# @hzab/form-render@0.5.4
|
|
221
|
+
|
|
222
|
+
- feat: LocationPicker mapInit 设置值取增加临时存储的 formatVal 的逻辑
|
|
223
|
+
|
|
224
|
+
# @hzab/form-render0.5.3
|
|
225
|
+
|
|
226
|
+
- feat: LocationPicker MapSearch 清除改为 input, map 请求优化
|
|
227
|
+
|
|
228
|
+
# @hzab/form-render0.5.2
|
|
229
|
+
|
|
230
|
+
- feat: TreeCheckbox tabBox 最外层允许配置成 tab
|
|
231
|
+
|
|
232
|
+
# @hzab/form-render0.5.1
|
|
233
|
+
|
|
234
|
+
- fix: LocationPicker 去除 changMode 参数,仅允许 点击地图选点
|
|
235
|
+
- fix: LocationPicker 获取地址逻辑修复
|
|
236
|
+
- fix: DatePicker 问题修复
|
|
237
|
+
|
|
238
|
+
# @hzab/form-render0.5.0
|
|
239
|
+
|
|
240
|
+
- fix: LocationPicker disabled || readOnly 不展示 Notice
|
|
241
|
+
- fix: LocationPicker 异步数据回填逻辑处理
|
|
242
|
+
- fix: LocationPicker 去除 isObjectRes 参数
|
|
243
|
+
|
|
244
|
+
# @hzab/form-render0.4.2
|
|
245
|
+
|
|
246
|
+
- LocationPicker getCurPosition 逻辑优化
|
|
247
|
+
|
|
248
|
+
# @hzab/form-render0.4.1
|
|
249
|
+
|
|
250
|
+
- LocationPicker useField 容错
|
|
251
|
+
|
|
252
|
+
# @hzab/form-render0.4.0
|
|
253
|
+
|
|
254
|
+
- LocationPicker 地图选点组件
|
|
255
|
+
- UserSelect 去除 defaultOpen 属性
|
|
256
|
+
|
|
257
|
+
# @hzab/form-render0.3.0
|
|
258
|
+
|
|
259
|
+
- feat: TreeCheckbox
|
|
260
|
+
|
|
261
|
+
# @hzab/form-render0.2.5
|
|
262
|
+
|
|
263
|
+
- fix: ant-form-inline style
|
|
264
|
+
|
|
265
|
+
# @hzab/form-render0.2.3
|
|
266
|
+
|
|
267
|
+
- export Components
|
|
268
|
+
|
|
269
|
+
# @hzab/form-render0.2.2
|
|
270
|
+
|
|
271
|
+
- Upload beforeUploadCheck
|
|
272
|
+
|
|
273
|
+
# @hzab/form-render0.2.1
|
|
274
|
+
|
|
275
|
+
- Upload preview video、img、audio
|
|
276
|
+
|
|
277
|
+
# @hzab/form-render0.2.0
|
|
278
|
+
|
|
279
|
+
- 人员选择组件
|
|
280
|
+
|
|
281
|
+
# @hzab/form-render0.1.0
|
|
282
|
+
|
|
283
|
+
- Upload 组件
|
|
284
|
+
|
|
285
|
+
# @hzab/form-render0.0.1
|
|
286
|
+
|
|
287
|
+
组件初始化
|
package/package.json
CHANGED
|
@@ -1,300 +1,305 @@
|
|
|
1
|
-
import React, { useEffect, useState, useRef, useCallback, useMemo } from "react";
|
|
2
|
-
import { Select, List, Avatar, Spin } from "antd";
|
|
3
|
-
import { connect, mapProps } from "@formily/react";
|
|
4
|
-
import { debounce, isObject
|
|
5
|
-
import type { LabelValue, ScrollPagination, RemoteSelectProps } from "./type";
|
|
6
|
-
|
|
7
|
-
import "./index.less";
|
|
8
|
-
|
|
9
|
-
const defaultListItemConfigs = [
|
|
10
|
-
{ label: "姓名:", key: "userName" },
|
|
11
|
-
{ label: "主部门:", key: "parentName" },
|
|
12
|
-
{ label: "主驻点:", key: "orgName" },
|
|
13
|
-
{ label: "手机号:", key: "phoneNumber" },
|
|
14
|
-
{ label: "身份证号:", key: "idnumber" },
|
|
15
|
-
];
|
|
16
|
-
|
|
17
|
-
const transfromLabelInValueData = (list: LabelValue[], labelKey: string, valueKey: string): LabelValue[] => {
|
|
18
|
-
try {
|
|
19
|
-
return list.map((item) => ({ ...item, label: item?.[labelKey], value: item?.[valueKey] }));
|
|
20
|
-
} catch (e) {
|
|
21
|
-
console.error(e);
|
|
22
|
-
return list;
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const RemoteSelect: React.FC<RemoteSelectProps> = ({
|
|
27
|
-
loadData,
|
|
28
|
-
searchData,
|
|
29
|
-
renderItem,
|
|
30
|
-
listItemConfigs,
|
|
31
|
-
labelKey = "userName",
|
|
32
|
-
valueKey = "userId",
|
|
33
|
-
disabledKey = "disabled",
|
|
34
|
-
initialPagination = {},
|
|
35
|
-
avataProps = {},
|
|
36
|
-
disabledStyle,
|
|
37
|
-
customItemNode,
|
|
38
|
-
labelInValue = false,
|
|
39
|
-
isClearable = false,
|
|
40
|
-
...selectProps
|
|
41
|
-
}) => {
|
|
42
|
-
const [search, setSearch] = useState("");
|
|
43
|
-
const [loading, setLoading] = useState(false);
|
|
44
|
-
const [loadingMore, setLoadingMore] = useState(false);
|
|
45
|
-
const [list, setList] = useState<LabelValue[]>([]);
|
|
46
|
-
const [cacheDeafultList, setCacheDeafultList] = useState<LabelValue[]>([]);
|
|
47
|
-
const [pagination, setPagination] = useState<ScrollPagination>({
|
|
48
|
-
pageNum: 1,
|
|
49
|
-
pageSize: 10,
|
|
50
|
-
...initialPagination,
|
|
51
|
-
});
|
|
52
|
-
const selectInstance = useRef<any>(null);
|
|
53
|
-
const total = useRef(0);
|
|
54
|
-
const initSearch = useRef(true);
|
|
55
|
-
|
|
56
|
-
const debounceLoadData = debounce(async (isScrollLoad = false) => {
|
|
57
|
-
try {
|
|
58
|
-
isScrollLoad ? setLoadingMore(true) : setLoading(true);
|
|
59
|
-
|
|
60
|
-
const result = await loadData(search, {
|
|
61
|
-
...pagination,
|
|
62
|
-
pageNum: isScrollLoad ? pagination.pageNum + 1 : 1,
|
|
63
|
-
});
|
|
64
|
-
const { list, pagination: resPagination } = result;
|
|
65
|
-
|
|
66
|
-
total.current = resPagination.total;
|
|
67
|
-
|
|
68
|
-
const transformatList: LabelValue[] = transfromLabelInValueData(list, labelKey, valueKey);
|
|
69
|
-
|
|
70
|
-
setList((prev) => (isScrollLoad ? [...prev, ...transformatList] : transformatList));
|
|
71
|
-
} finally {
|
|
72
|
-
isScrollLoad ? setLoadingMore(false) : setLoading(false);
|
|
73
|
-
}
|
|
74
|
-
}, 500);
|
|
75
|
-
|
|
76
|
-
const debounceHandleScroll = async (e: React.UIEvent<HTMLDivElement>) => {
|
|
77
|
-
const { scrollTop, clientHeight, scrollHeight } = e.currentTarget;
|
|
78
|
-
const isNearBottom = scrollHeight - scrollTop - clientHeight < 30;
|
|
79
|
-
|
|
80
|
-
if (isNearBottom && !loadingMore && list.length <= total.current) {
|
|
81
|
-
await getData(true);
|
|
82
|
-
setPagination((pre) => ({ ...pre, pageNum: pagination.pageNum + 1 }));
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
const getData = useCallback(debounceLoadData, [search, pagination, loadData]);
|
|
87
|
-
|
|
88
|
-
// 处理滚动加载
|
|
89
|
-
const handleScroll = useCallback(debounceHandleScroll, [search, loadingMore, loadData]);
|
|
90
|
-
|
|
91
|
-
// 重置list滚动条
|
|
92
|
-
const resetListScroll = () => {
|
|
93
|
-
const listNode = document.getElementById("abt-list");
|
|
94
|
-
listNode && listNode.scrollTo({ top: 0, behavior: "auto" });
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// 处理搜索
|
|
98
|
-
const handleSearch = debounce((value: string) => {
|
|
99
|
-
resetListScroll();
|
|
100
|
-
setSearch(value);
|
|
101
|
-
setPagination((prev) => ({ ...prev, pageNum: 1 }));
|
|
102
|
-
}, 1000);
|
|
103
|
-
|
|
104
|
-
const handleOnDropdownVisibleChange = (open: boolean) => {
|
|
105
|
-
if (!isClearable) return;
|
|
106
|
-
if (open) {
|
|
107
|
-
getData();
|
|
108
|
-
} else {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
filterOption={false}
|
|
275
|
-
|
|
276
|
-
placeholder="请选择人员"
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
},
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
1
|
+
import React, { useEffect, useState, useRef, useCallback, useMemo } from "react";
|
|
2
|
+
import { Select, List, Avatar, Spin } from "antd";
|
|
3
|
+
import { connect, mapProps } from "@formily/react";
|
|
4
|
+
import { debounce, isObject } from "lodash";
|
|
5
|
+
import type { LabelValue, ScrollPagination, RemoteSelectProps } from "./type";
|
|
6
|
+
|
|
7
|
+
import "./index.less";
|
|
8
|
+
|
|
9
|
+
const defaultListItemConfigs = [
|
|
10
|
+
{ label: "姓名:", key: "userName" },
|
|
11
|
+
{ label: "主部门:", key: "parentName" },
|
|
12
|
+
{ label: "主驻点:", key: "orgName" },
|
|
13
|
+
{ label: "手机号:", key: "phoneNumber" },
|
|
14
|
+
{ label: "身份证号:", key: "idnumber" },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const transfromLabelInValueData = (list: LabelValue[], labelKey: string, valueKey: string): LabelValue[] => {
|
|
18
|
+
try {
|
|
19
|
+
return list.map((item) => ({ ...item, label: item?.[labelKey], value: item?.[valueKey] }));
|
|
20
|
+
} catch (e) {
|
|
21
|
+
console.error(e);
|
|
22
|
+
return list;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const RemoteSelect: React.FC<RemoteSelectProps> = ({
|
|
27
|
+
loadData,
|
|
28
|
+
searchData,
|
|
29
|
+
renderItem,
|
|
30
|
+
listItemConfigs,
|
|
31
|
+
labelKey = "userName",
|
|
32
|
+
valueKey = "userId",
|
|
33
|
+
disabledKey = "disabled",
|
|
34
|
+
initialPagination = {},
|
|
35
|
+
avataProps = {},
|
|
36
|
+
disabledStyle,
|
|
37
|
+
customItemNode,
|
|
38
|
+
labelInValue = false,
|
|
39
|
+
isClearable = false,
|
|
40
|
+
...selectProps
|
|
41
|
+
}) => {
|
|
42
|
+
const [search, setSearch] = useState("");
|
|
43
|
+
const [loading, setLoading] = useState(false);
|
|
44
|
+
const [loadingMore, setLoadingMore] = useState(false);
|
|
45
|
+
const [list, setList] = useState<LabelValue[]>([]);
|
|
46
|
+
// const [cacheDeafultList, setCacheDeafultList] = useState<LabelValue[]>([]);
|
|
47
|
+
const [pagination, setPagination] = useState<ScrollPagination>({
|
|
48
|
+
pageNum: 1,
|
|
49
|
+
pageSize: 10,
|
|
50
|
+
...initialPagination,
|
|
51
|
+
});
|
|
52
|
+
const selectInstance = useRef<any>(null);
|
|
53
|
+
const total = useRef(0);
|
|
54
|
+
const initSearch = useRef(true);
|
|
55
|
+
|
|
56
|
+
const debounceLoadData = debounce(async (isScrollLoad = false) => {
|
|
57
|
+
try {
|
|
58
|
+
isScrollLoad ? setLoadingMore(true) : setLoading(true);
|
|
59
|
+
|
|
60
|
+
const result = await loadData(search, {
|
|
61
|
+
...pagination,
|
|
62
|
+
pageNum: isScrollLoad ? pagination.pageNum + 1 : 1,
|
|
63
|
+
});
|
|
64
|
+
const { list, pagination: resPagination } = result;
|
|
65
|
+
|
|
66
|
+
total.current = resPagination.total;
|
|
67
|
+
|
|
68
|
+
const transformatList: LabelValue[] = transfromLabelInValueData(list, labelKey, valueKey);
|
|
69
|
+
|
|
70
|
+
setList((prev) => (isScrollLoad ? [...prev, ...transformatList] : transformatList));
|
|
71
|
+
} finally {
|
|
72
|
+
isScrollLoad ? setLoadingMore(false) : setLoading(false);
|
|
73
|
+
}
|
|
74
|
+
}, 500);
|
|
75
|
+
|
|
76
|
+
const debounceHandleScroll = async (e: React.UIEvent<HTMLDivElement>) => {
|
|
77
|
+
const { scrollTop, clientHeight, scrollHeight } = e.currentTarget;
|
|
78
|
+
const isNearBottom = scrollHeight - scrollTop - clientHeight < 30;
|
|
79
|
+
|
|
80
|
+
if (isNearBottom && !loadingMore && list.length <= total.current) {
|
|
81
|
+
await getData(true);
|
|
82
|
+
setPagination((pre) => ({ ...pre, pageNum: pagination.pageNum + 1 }));
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const getData = useCallback(debounceLoadData, [search, pagination, loadData]);
|
|
87
|
+
|
|
88
|
+
// 处理滚动加载
|
|
89
|
+
const handleScroll = useCallback(debounceHandleScroll, [search, loadingMore, loadData]);
|
|
90
|
+
|
|
91
|
+
// 重置list滚动条
|
|
92
|
+
const resetListScroll = () => {
|
|
93
|
+
const listNode = document.getElementById("abt-list");
|
|
94
|
+
listNode && listNode.scrollTo({ top: 0, behavior: "auto" });
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// 处理搜索
|
|
98
|
+
const handleSearch = debounce((value: string) => {
|
|
99
|
+
resetListScroll();
|
|
100
|
+
setSearch(value);
|
|
101
|
+
setPagination((prev) => ({ ...prev, pageNum: 1 }));
|
|
102
|
+
}, 1000);
|
|
103
|
+
|
|
104
|
+
const handleOnDropdownVisibleChange = (open: boolean) => {
|
|
105
|
+
if (!isClearable) return;
|
|
106
|
+
if (open) {
|
|
107
|
+
getData();
|
|
108
|
+
} else {
|
|
109
|
+
reset();
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const reset = () => {
|
|
114
|
+
setSearch("");
|
|
115
|
+
resetListScroll();
|
|
116
|
+
setList([]);
|
|
117
|
+
setPagination((prev) => ({ ...prev, pageNum: 1 }));
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// 处理选项点击事件
|
|
121
|
+
const handleItemClick = (item: LabelValue) => {
|
|
122
|
+
const { value: currentValue, mode, onChange } = selectProps;
|
|
123
|
+
const itemId = item.value;
|
|
124
|
+
|
|
125
|
+
// 多选模式处理
|
|
126
|
+
const handleMultipleSelection = () => {
|
|
127
|
+
const selectedOptions: any[] = Array.isArray(currentValue) ? currentValue : [currentValue];
|
|
128
|
+
|
|
129
|
+
if (labelInValue) {
|
|
130
|
+
const isSelected = selectedOptions.some((opt) => opt.value === itemId);
|
|
131
|
+
|
|
132
|
+
return isSelected
|
|
133
|
+
? selectedOptions.filter((opt) => opt.value !== itemId) // 移除已选项
|
|
134
|
+
: [...selectedOptions, item]; // 添加新选项
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const isSelected = selectedOptions.some((opt) => opt === itemId);
|
|
138
|
+
|
|
139
|
+
return isSelected
|
|
140
|
+
? selectedOptions.filter((opt) => opt !== itemId) // 移除已选项
|
|
141
|
+
: [...selectedOptions, item]; // 添加新选项
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// 单选模式处理
|
|
145
|
+
const handleSingleSelection = () => {
|
|
146
|
+
const isCurrentSelected = (currentValue as LabelValue)?.value === itemId;
|
|
147
|
+
return isCurrentSelected ? undefined : item;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
let resultValue: string | number | any[] | LabelValue;
|
|
151
|
+
|
|
152
|
+
// 执行模式对应处理
|
|
153
|
+
const newValue = mode === "multiple" ? handleMultipleSelection() : handleSingleSelection();
|
|
154
|
+
|
|
155
|
+
if (mode === "multiple") {
|
|
156
|
+
if (labelInValue) resultValue = newValue;
|
|
157
|
+
else resultValue = newValue.map((x: LabelValue | string | number) => (typeof x === "object" ? x?.value : x));
|
|
158
|
+
} else {
|
|
159
|
+
labelInValue ? (resultValue = newValue) : (resultValue = (newValue as unknown as LabelValue).value);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// 触发变更回调
|
|
163
|
+
onChange?.(resultValue, currentValue as any);
|
|
164
|
+
|
|
165
|
+
// 单选模式自动关闭下拉框
|
|
166
|
+
if (mode !== "multiple" && selectInstance.current) selectInstance.current.blur();
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// 合并配置
|
|
170
|
+
const itemConfigs = useMemo(() => {
|
|
171
|
+
if (Array.isArray(listItemConfigs) && listItemConfigs?.length) return listItemConfigs;
|
|
172
|
+
return defaultListItemConfigs;
|
|
173
|
+
}, [listItemConfigs]);
|
|
174
|
+
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
getData();
|
|
177
|
+
}, [search]);
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
// 当value为一个id或者id数组时,需要进行数据查询用以回显label等信息
|
|
180
|
+
if (selectProps.value && typeof searchData === "function" && initSearch.current) {
|
|
181
|
+
searchData?.(selectProps.value).then((res: Record<string, any>) => {
|
|
182
|
+
const listData = transfromLabelInValueData(res.list || [], labelKey, valueKey);
|
|
183
|
+
// setCacheDeafultList(listData);
|
|
184
|
+
setList(listData);
|
|
185
|
+
});
|
|
186
|
+
// 只有初始化时执行
|
|
187
|
+
initSearch.current = false;
|
|
188
|
+
}
|
|
189
|
+
}, [selectProps.value]);
|
|
190
|
+
|
|
191
|
+
// 默认渲染项(增加选中状态和点击处理)
|
|
192
|
+
const defaultRenderItem = useCallback(
|
|
193
|
+
(item: LabelValue) => {
|
|
194
|
+
const { mode, value: selectedValue } = selectProps;
|
|
195
|
+
const { value, [disabledKey]: isDisabled = false } = item;
|
|
196
|
+
// 选中状态判断
|
|
197
|
+
const getSelectionStatus = () => {
|
|
198
|
+
if (mode === "multiple") {
|
|
199
|
+
if (!Array.isArray(selectedValue)) return false;
|
|
200
|
+
const selectedValues = (selectedValue || [])?.map((opt) =>
|
|
201
|
+
(isObject(opt) as unknown as Record<string, any>) ? opt?.value ?? opt?.value : opt,
|
|
202
|
+
);
|
|
203
|
+
return selectedValues.includes(value);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return isObject(selectedValue) ? (selectedValue as LabelValue)?.value === value : selectedValue === value;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// 禁用样式生成
|
|
210
|
+
const generateStyle = (disabled: boolean): React.CSSProperties => {
|
|
211
|
+
if (typeof disabledStyle === "function") {
|
|
212
|
+
return disabledStyle(disabled);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
217
|
+
backgroundColor: disabled ? "#f0f0f0" : getSelectionStatus() ? "#e6f7ff" : "inherit",
|
|
218
|
+
color: disabled ? "#999" : "inherit",
|
|
219
|
+
filter: disabled ? "grayscale(100%)" : "none",
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// 头像组件
|
|
224
|
+
const avatarComponent = <Avatar alt={item.userName} size={60} {...avataProps} src={item.avatar} />;
|
|
225
|
+
|
|
226
|
+
// 用户信息列表
|
|
227
|
+
const userInfoContent = (
|
|
228
|
+
<ul className="abt-user-item-info">
|
|
229
|
+
{itemConfigs.map((configItem, index) => (
|
|
230
|
+
<li key={configItem?.key || index} className="abt-user-item-info__item">
|
|
231
|
+
<span>{configItem?.label}</span>
|
|
232
|
+
<span>{item?.[configItem.key]}</span>
|
|
233
|
+
</li>
|
|
234
|
+
))}
|
|
235
|
+
</ul>
|
|
236
|
+
);
|
|
237
|
+
const itemStyle = generateStyle(isDisabled);
|
|
238
|
+
|
|
239
|
+
const renderCustomItemNode = typeof customItemNode === "function" ? customItemNode?.(item, itemStyle) : null;
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<List.Item key={value} onClick={() => !isDisabled && handleItemClick(item)} style={itemStyle}>
|
|
243
|
+
{renderCustomItemNode || (
|
|
244
|
+
<div className="abt-user-item" key={item?.value}>
|
|
245
|
+
<div className="abt-user-item-avatar">{avatarComponent}</div>
|
|
246
|
+
{userInfoContent}
|
|
247
|
+
</div>
|
|
248
|
+
)}
|
|
249
|
+
</List.Item>
|
|
250
|
+
);
|
|
251
|
+
},
|
|
252
|
+
[selectProps.value, list?.length],
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
// 自定义下拉内容
|
|
256
|
+
const dropdownRender = () => (
|
|
257
|
+
<div>
|
|
258
|
+
<Spin spinning={loading}>
|
|
259
|
+
<List
|
|
260
|
+
id={"abt-list"}
|
|
261
|
+
loading={loadingMore}
|
|
262
|
+
dataSource={list}
|
|
263
|
+
renderItem={renderItem ? renderItem : defaultRenderItem}
|
|
264
|
+
/*@ts-ignore*/
|
|
265
|
+
onScroll={handleScroll}
|
|
266
|
+
style={{ maxHeight: 250, overflowY: "auto" }}
|
|
267
|
+
/>
|
|
268
|
+
</Spin>
|
|
269
|
+
</div>
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
return (
|
|
273
|
+
<Select
|
|
274
|
+
filterOption={false}
|
|
275
|
+
showSearch
|
|
276
|
+
placeholder="请选择人员"
|
|
277
|
+
{...selectProps}
|
|
278
|
+
ref={selectInstance}
|
|
279
|
+
onDropdownVisibleChange={handleOnDropdownVisibleChange}
|
|
280
|
+
onSearch={handleSearch}
|
|
281
|
+
dropdownRender={dropdownRender}
|
|
282
|
+
options={list.map((item) => ({
|
|
283
|
+
value: item?.[valueKey] || item?.userId,
|
|
284
|
+
label: item?.[labelKey] || item.userName,
|
|
285
|
+
...item,
|
|
286
|
+
}))}
|
|
287
|
+
/>
|
|
288
|
+
);
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
const PersonnelSelect = connect(
|
|
292
|
+
RemoteSelect,
|
|
293
|
+
mapProps(
|
|
294
|
+
{
|
|
295
|
+
loading: true,
|
|
296
|
+
},
|
|
297
|
+
(props) => {
|
|
298
|
+
return {
|
|
299
|
+
...props,
|
|
300
|
+
};
|
|
301
|
+
},
|
|
302
|
+
),
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
export { RemoteSelect, PersonnelSelect };
|
|
@@ -60,8 +60,9 @@ export const mergeFileName = function (fileName, str = "") {
|
|
|
60
60
|
if (typeof fileName !== "string") {
|
|
61
61
|
return "";
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
const suffix = fileName?.match(
|
|
63
|
+
|
|
64
|
+
const suffix = fileName?.match(/\.([^\/.]+)$/)?.[1] || "";
|
|
65
|
+
const name = fileName?.match(/([^\/]+)\.[^.]+$/)?.[1] || "";
|
|
65
66
|
return `${name}${str ?? ""}.${suffix}`;
|
|
66
67
|
};
|
|
67
68
|
|