@basestone/hooks 1.3.7 → 1.3.9
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/README.md +423 -29
- package/dist/design-hooks.es.prod.d.ts +4 -6
- package/dist/design-hooks.es.prod.js +98 -98
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,69 +1,463 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @basestone/hooks
|
|
2
2
|
|
|
3
|
+
一套用于 React + Ant Design 应用的生产级 Hooks 库,提供表格管理、模态框管理、表单提交、数据请求等常用功能。
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@basestone/hooks)
|
|
6
|
+
[](https://github.com/base-stone/hooks/blob/master/LICENSE)
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
## ✨ 特性
|
|
9
|
+
|
|
10
|
+
- 🎯 **开箱即用** - 提供常用业务场景的完整解决方案
|
|
11
|
+
- 💪 **TypeScript** - 完整的类型定义和类型推导
|
|
12
|
+
- 🎨 **Ant Design** - 深度集成 Ant Design 组件
|
|
13
|
+
- ⚡️ **性能优化** - 内置性能优化和记忆化
|
|
14
|
+
- 🔧 **灵活配置** - 支持全局配置和局部定制
|
|
7
15
|
|
|
8
|
-
|
|
16
|
+
## 📦 安装
|
|
9
17
|
|
|
18
|
+
```bash
|
|
19
|
+
pnpm add @basestone/hooks
|
|
20
|
+
# or
|
|
21
|
+
npm install @basestone/hooks
|
|
22
|
+
# or
|
|
23
|
+
yarn add @basestone/hooks
|
|
10
24
|
```
|
|
11
25
|
|
|
26
|
+
## 📚 Hooks 列表
|
|
12
27
|
|
|
13
|
-
|
|
28
|
+
- [useTableList](#usetablelist---表格管理) - 表格管理(分页、排序、加载等)
|
|
29
|
+
- [useCreateModal](#usecreatemodal---模态框管理) - 模态框/抽屉管理
|
|
30
|
+
- [useSelectOptions](#useselectoptions---下拉选项管理) - 下拉选项管理
|
|
31
|
+
- [useRequestQuery](#userequestquery---数据请求) - 通用数据请求
|
|
32
|
+
- [useFormSubmit](#useformsubmit---表单提交) - 表单提交处理
|
|
33
|
+
- [useMemoizedFn](#usememoizedfn---函数记忆化) - 函数记忆化
|
|
14
34
|
|
|
35
|
+
## 🔧 Claude Code Skill
|
|
15
36
|
|
|
16
|
-
|
|
37
|
+
本库提供了 Claude Code Skill,可以在使用 Claude Code 开发时快速获取帮助和代码示例。
|
|
38
|
+
|
|
39
|
+
查看 [Skill 文档](./.claude/skills/README.md) 了解如何在你的项目中使用。
|
|
40
|
+
|
|
41
|
+
## 📖 使用文档
|
|
17
42
|
|
|
18
|
-
|
|
19
|
-
|
|
43
|
+
|
|
44
|
+
### useTableList - 表格管理
|
|
45
|
+
|
|
46
|
+
提供完整的表格管理功能,包括分页、排序、加载状态、行选择等。
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import { useTableList } from '@basestone/hooks'
|
|
50
|
+
import { Table } from 'antd'
|
|
51
|
+
|
|
52
|
+
function UserList() {
|
|
53
|
+
const { tableProps, search, refresh, reset, queryParams, selectedRowKeys } = useTableList({
|
|
54
|
+
queryFn: async (params) => {
|
|
55
|
+
// API 返回格式: { status: 'success', data: { list: [], totalCount: 0 } }
|
|
56
|
+
return await getUserList(params)
|
|
57
|
+
},
|
|
20
58
|
params: {
|
|
21
59
|
orderField: 'createDate',
|
|
22
60
|
orderType: 'DESC',
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
61
|
+
status: 'active'
|
|
62
|
+
},
|
|
63
|
+
rowSelection: true // 启用行选择
|
|
26
64
|
})
|
|
27
|
-
|
|
28
|
-
<Table rowKey="id" scroll={{ x: 'max-content' }} columns={columns} {...tableProps} />
|
|
29
65
|
|
|
66
|
+
return (
|
|
67
|
+
<div>
|
|
68
|
+
<button onClick={() => search({ keyword: 'test' })}>搜索</button>
|
|
69
|
+
<button onClick={() => refresh()}>刷新</button>
|
|
70
|
+
<Table
|
|
71
|
+
rowKey="id"
|
|
72
|
+
scroll={{ x: 'max-content' }}
|
|
73
|
+
columns={columns}
|
|
74
|
+
{...tableProps}
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
30
79
|
```
|
|
31
80
|
|
|
32
|
-
|
|
81
|
+
**API:**
|
|
82
|
+
- `tableProps` - Ant Design Table 所需的所有属性
|
|
83
|
+
- `search(params)` - 搜索并重置到第一页
|
|
84
|
+
- `refresh(params)` - 刷新当前页
|
|
85
|
+
- `reset(params)` - 重置查询参数
|
|
86
|
+
- `queryParams` - 当前查询参数
|
|
87
|
+
- `selectedRowKeys` - 选中的行 keys
|
|
33
88
|
|
|
89
|
+
### useCreateModal - 模态框管理
|
|
34
90
|
|
|
35
|
-
|
|
91
|
+
使用 zustand 管理多个模态框的状态,支持 Modal 和 Drawer。
|
|
36
92
|
|
|
37
|
-
|
|
93
|
+
```tsx
|
|
94
|
+
import { useCreateModal } from '@basestone/hooks'
|
|
95
|
+
import { Modal, Drawer } from 'antd'
|
|
38
96
|
|
|
39
|
-
|
|
97
|
+
function UserManagement() {
|
|
98
|
+
const { editModal, viewModal, open, close, toggle } = useCreateModal({
|
|
99
|
+
edit: {
|
|
100
|
+
width: 600,
|
|
101
|
+
title: (data) => data?.id ? '编辑用户' : '创建用户',
|
|
102
|
+
centered: true,
|
|
103
|
+
maskClosable: false
|
|
104
|
+
},
|
|
105
|
+
view: {
|
|
106
|
+
width: 800,
|
|
107
|
+
title: '用户详情',
|
|
108
|
+
placement: 'right' // Drawer 配置
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<div>
|
|
114
|
+
<button onClick={() => open('edit', { id: 1, name: 'John' })}>
|
|
115
|
+
编辑用户
|
|
116
|
+
</button>
|
|
40
117
|
|
|
118
|
+
{/* 作为 Modal 使用 */}
|
|
119
|
+
<Modal {...editModal.modalProps}>
|
|
120
|
+
<div>用户数据: {JSON.stringify(editModal.data)}</div>
|
|
121
|
+
</Modal>
|
|
122
|
+
|
|
123
|
+
{/* 作为 Drawer 使用 */}
|
|
124
|
+
<Drawer {...viewModal.drawerProps}>
|
|
125
|
+
<div>用户详情: {JSON.stringify(viewModal.data)}</div>
|
|
126
|
+
</Drawer>
|
|
127
|
+
</div>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
41
130
|
```
|
|
42
131
|
|
|
132
|
+
**API:**
|
|
133
|
+
- `{name}Modal.modalProps` - Modal 组件属性
|
|
134
|
+
- `{name}Modal.drawerProps` - Drawer 组件属性
|
|
135
|
+
- `{name}Modal.visible` - 可见状态
|
|
136
|
+
- `{name}Modal.data` - 传入的数据
|
|
137
|
+
- `open(type, data)` - 打开指定模态框
|
|
138
|
+
- `close(type)` - 关闭指定模态框
|
|
139
|
+
- `toggle(type, data)` - 切换指定模态框
|
|
140
|
+
|
|
43
141
|
|
|
44
|
-
### useSelectOptions
|
|
142
|
+
### useSelectOptions - 下拉选项管理
|
|
45
143
|
|
|
144
|
+
自动获取和管理下拉选项,并创建 value-label 映射。
|
|
46
145
|
|
|
146
|
+
```tsx
|
|
147
|
+
import { useSelectOptions } from '@basestone/hooks'
|
|
148
|
+
import { Select } from 'antd'
|
|
149
|
+
|
|
150
|
+
function UserFilter() {
|
|
151
|
+
const { departmentOptions, departmentMap, loading, refresh } = useSelectOptions({
|
|
152
|
+
queryFn: async (params) => {
|
|
153
|
+
// API 返回格式: { status: 'success', data: [] }
|
|
154
|
+
return await getDepartmentList(params)
|
|
155
|
+
},
|
|
156
|
+
params: { active: true },
|
|
157
|
+
dataKey: 'department', // 会创建 departmentOptions 和 departmentMap
|
|
158
|
+
fieldNames: {
|
|
159
|
+
label: 'departmentName',
|
|
160
|
+
value: 'departmentId'
|
|
161
|
+
},
|
|
162
|
+
transform: (data) => data.filter(item => item.visible) // 可选的数据转换
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<Select
|
|
167
|
+
options={departmentOptions}
|
|
168
|
+
loading={loading}
|
|
169
|
+
onChange={(value) => {
|
|
170
|
+
console.log('选中值:', value)
|
|
171
|
+
console.log('对应标签:', departmentMap.get(value))
|
|
172
|
+
}}
|
|
173
|
+
/>
|
|
174
|
+
)
|
|
175
|
+
}
|
|
47
176
|
```
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
177
|
+
|
|
178
|
+
**API:**
|
|
179
|
+
- `{dataKey}Options` - 格式化后的选项数组 `{ label, value, data }`
|
|
180
|
+
- `{dataKey}Map` - value 到 label 的映射 Map
|
|
181
|
+
- `loading` - 加载状态
|
|
182
|
+
- `refresh()` - 刷新选项
|
|
183
|
+
|
|
184
|
+
### useRequestQuery - 数据请求
|
|
185
|
+
|
|
186
|
+
通用的数据请求 Hook,支持 Object 和 Array 类型数据。
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
import { useRequestQuery } from '@basestone/hooks'
|
|
190
|
+
|
|
191
|
+
function UserProfile({ userId }) {
|
|
192
|
+
// 请求单个对象
|
|
193
|
+
const { userInfo, setUserInfo, loading, refresh } = useRequestQuery({
|
|
194
|
+
queryFn: async (params) => {
|
|
195
|
+
// API 返回格式: { status: 'success', data: {...} }
|
|
196
|
+
return await getUserInfo(params)
|
|
197
|
+
},
|
|
198
|
+
params: { userId },
|
|
199
|
+
dataKey: 'userInfo',
|
|
200
|
+
dataType: 'Object',
|
|
201
|
+
initialValue: { name: '', email: '' },
|
|
202
|
+
transform: (data) => ({
|
|
203
|
+
...data,
|
|
204
|
+
fullName: `${data.firstName} ${data.lastName}`
|
|
205
|
+
}),
|
|
206
|
+
success: (data) => {
|
|
207
|
+
console.log('数据加载成功:', data)
|
|
208
|
+
}
|
|
52
209
|
})
|
|
53
210
|
|
|
211
|
+
// 请求数组数据
|
|
212
|
+
const { notificationList, setNotificationList } = useRequestQuery({
|
|
213
|
+
queryFn: getNotificationList,
|
|
214
|
+
params: { userId },
|
|
215
|
+
dataKey: 'notificationList',
|
|
216
|
+
dataType: 'Array',
|
|
217
|
+
initialValue: []
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
// 手动更新数据
|
|
221
|
+
const handleUpdateName = () => {
|
|
222
|
+
setUserInfo(prev => ({ ...prev, name: '新名字' }))
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const markAsRead = (id) => {
|
|
226
|
+
setNotificationList(prev =>
|
|
227
|
+
prev.map(item => item.id === id ? { ...item, read: true } : item)
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return (
|
|
232
|
+
<div>
|
|
233
|
+
{loading ? '加载中...' : (
|
|
234
|
+
<div>
|
|
235
|
+
<h1>{userInfo?.fullName}</h1>
|
|
236
|
+
<p>{userInfo?.email}</p>
|
|
237
|
+
<button onClick={handleUpdateName}>修改名字</button>
|
|
238
|
+
</div>
|
|
239
|
+
)}
|
|
240
|
+
</div>
|
|
241
|
+
)
|
|
242
|
+
}
|
|
54
243
|
```
|
|
55
244
|
|
|
56
|
-
|
|
245
|
+
**API:**
|
|
246
|
+
- `{dataKey}` - 请求到的数据
|
|
247
|
+
- `set{DataKey}` - 手动更新数据的函数,支持直接设置或函数式更新
|
|
248
|
+
- `loading` - 加载状态
|
|
249
|
+
- `refresh(params)` - 刷新数据
|
|
250
|
+
|
|
251
|
+
### useFormSubmit - 表单提交
|
|
57
252
|
|
|
253
|
+
处理表单提交,自动管理加载状态和消息提示。
|
|
254
|
+
|
|
255
|
+
```tsx
|
|
256
|
+
import { useFormSubmit } from '@basestone/hooks'
|
|
257
|
+
import { Form, Input, Button, App } from 'antd'
|
|
258
|
+
|
|
259
|
+
function UserForm({ onSuccess }) {
|
|
260
|
+
const [form] = Form.useForm()
|
|
261
|
+
|
|
262
|
+
const { loading, submit } = useFormSubmit(
|
|
263
|
+
async (values) => {
|
|
264
|
+
// API 返回格式: { status: 'success', info: '操作成功' }
|
|
265
|
+
return await createUser(values)
|
|
266
|
+
},
|
|
267
|
+
(result) => {
|
|
268
|
+
form.resetFields()
|
|
269
|
+
onSuccess?.(result)
|
|
270
|
+
}
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
return (
|
|
274
|
+
<App> {/* 必需:message API 依赖 */}
|
|
275
|
+
<Form form={form} onFinish={submit}>
|
|
276
|
+
<Form.Item name="name" label="姓名" rules={[{ required: true }]}>
|
|
277
|
+
<Input />
|
|
278
|
+
</Form.Item>
|
|
279
|
+
<Button type="primary" htmlType="submit" loading={loading}>
|
|
280
|
+
提交
|
|
281
|
+
</Button>
|
|
282
|
+
</Form>
|
|
283
|
+
</App>
|
|
284
|
+
)
|
|
285
|
+
}
|
|
58
286
|
```
|
|
59
287
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
288
|
+
**API:**
|
|
289
|
+
- `loading` - 提交中状态
|
|
290
|
+
- `submit(values)` - 提交函数
|
|
291
|
+
|
|
292
|
+
### useMemoizedFn - 函数记忆化
|
|
293
|
+
|
|
294
|
+
创建一个稳定引用的函数,但始终调用最新的实现。
|
|
295
|
+
|
|
296
|
+
```tsx
|
|
297
|
+
import { useMemoizedFn } from '@basestone/hooks'
|
|
298
|
+
import { useEffect } from 'react'
|
|
299
|
+
|
|
300
|
+
function Component() {
|
|
301
|
+
const [count, setCount] = useState(0)
|
|
302
|
+
|
|
303
|
+
// 函数引用永不改变,但总是调用最新的实现
|
|
304
|
+
const handleClick = useMemoizedFn(() => {
|
|
305
|
+
console.log('当前 count:', count) // 总是打印最新的 count
|
|
306
|
+
setCount(count + 1)
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
useEffect(() => {
|
|
310
|
+
// handleClick 不会导致 effect 重新运行
|
|
311
|
+
}, [handleClick])
|
|
312
|
+
|
|
313
|
+
return <button onClick={handleClick}>点击 {count}</button>
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## 🎯 完整示例
|
|
318
|
+
|
|
319
|
+
```tsx
|
|
320
|
+
import {
|
|
321
|
+
useTableList,
|
|
322
|
+
useCreateModal,
|
|
323
|
+
useSelectOptions,
|
|
324
|
+
useFormSubmit
|
|
325
|
+
} from '@basestone/hooks'
|
|
326
|
+
import { Table, Modal, Form, Input, Select, Button, Space } from 'antd'
|
|
327
|
+
|
|
328
|
+
function UserManagement() {
|
|
329
|
+
const [form] = Form.useForm()
|
|
330
|
+
|
|
331
|
+
// 表格管理
|
|
332
|
+
const { tableProps, refresh } = useTableList({
|
|
333
|
+
queryFn: getUserList,
|
|
334
|
+
params: { status: 'active' },
|
|
335
|
+
rowSelection: true
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
// 模态框管理
|
|
339
|
+
const { editModal, open, close } = useCreateModal({
|
|
340
|
+
edit: {
|
|
341
|
+
width: 600,
|
|
342
|
+
title: (data) => data?.id ? '编辑' : '创建'
|
|
66
343
|
}
|
|
67
344
|
})
|
|
68
345
|
|
|
346
|
+
// 下拉选项
|
|
347
|
+
const { roleOptions } = useSelectOptions({
|
|
348
|
+
queryFn: getRoleList,
|
|
349
|
+
dataKey: 'role',
|
|
350
|
+
fieldNames: { label: 'roleName', value: 'roleId' }
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
// 表单提交
|
|
354
|
+
const { loading, submit } = useFormSubmit(
|
|
355
|
+
async (values) => {
|
|
356
|
+
const api = editModal.data?.id ? updateUser : createUser
|
|
357
|
+
return api({ ...values, id: editModal.data?.id })
|
|
358
|
+
},
|
|
359
|
+
() => {
|
|
360
|
+
close('edit')
|
|
361
|
+
refresh()
|
|
362
|
+
}
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
const columns = [
|
|
366
|
+
{ title: '姓名', dataIndex: 'name' },
|
|
367
|
+
{ title: '邮箱', dataIndex: 'email' },
|
|
368
|
+
{
|
|
369
|
+
title: '操作',
|
|
370
|
+
render: (_, record) => (
|
|
371
|
+
<Space>
|
|
372
|
+
<Button onClick={() => open('edit', record)}>编辑</Button>
|
|
373
|
+
</Space>
|
|
374
|
+
)
|
|
375
|
+
}
|
|
376
|
+
]
|
|
377
|
+
|
|
378
|
+
return (
|
|
379
|
+
<div>
|
|
380
|
+
<Button onClick={() => open('edit')}>创建用户</Button>
|
|
381
|
+
<Table rowKey="id" columns={columns} {...tableProps} />
|
|
382
|
+
|
|
383
|
+
<Modal {...editModal.modalProps}>
|
|
384
|
+
<Form form={form} onFinish={submit} initialValues={editModal.data}>
|
|
385
|
+
<Form.Item name="name" label="姓名" rules={[{ required: true }]}>
|
|
386
|
+
<Input />
|
|
387
|
+
</Form.Item>
|
|
388
|
+
<Form.Item name="roleId" label="角色">
|
|
389
|
+
<Select options={roleOptions} />
|
|
390
|
+
</Form.Item>
|
|
391
|
+
<Button type="primary" htmlType="submit" loading={loading}>
|
|
392
|
+
提交
|
|
393
|
+
</Button>
|
|
394
|
+
</Form>
|
|
395
|
+
</Modal>
|
|
396
|
+
</div>
|
|
397
|
+
)
|
|
398
|
+
}
|
|
69
399
|
```
|
|
400
|
+
|
|
401
|
+
## 🔌 API 响应格式
|
|
402
|
+
|
|
403
|
+
所有请求函数应返回以下格式:
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
// 成功响应
|
|
407
|
+
{
|
|
408
|
+
status: 'success',
|
|
409
|
+
data: any, // 实际数据
|
|
410
|
+
info?: string // 可选的消息
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// useTableList 专用格式
|
|
414
|
+
{
|
|
415
|
+
status: 'success',
|
|
416
|
+
data: {
|
|
417
|
+
list: any[], // 数据列表
|
|
418
|
+
totalCount: number // 总数
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## 🎨 全局配置
|
|
424
|
+
|
|
425
|
+
### 表格全局配置
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
import { configureTableOption } from '@basestone/hooks'
|
|
429
|
+
|
|
430
|
+
configureTableOption({
|
|
431
|
+
sortField: ['orderType', 'orderField'], // 排序字段名
|
|
432
|
+
sortOrder: ['ASC', 'DESC'], // 排序顺序值
|
|
433
|
+
pageSize: 20 // 默认每页条数
|
|
434
|
+
})
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## 💡 最佳实践
|
|
438
|
+
|
|
439
|
+
1. **错误处理**: 所有 hooks 内部处理错误,但应确保 API 返回正确的响应格式
|
|
440
|
+
2. **加载状态**: 利用提供的 loading 状态提升用户体验
|
|
441
|
+
3. **函数记忆化**: 对于传递给子组件的回调,使用 `useMemoizedFn`
|
|
442
|
+
4. **模态框状态**: 模态框状态使用 zustand 全局管理,跨渲染保持
|
|
443
|
+
5. **类型安全**: 使用 TypeScript 泛型获得更好的类型推导
|
|
444
|
+
|
|
445
|
+
## 📄 依赖
|
|
446
|
+
|
|
447
|
+
- `react` ^19.0.0
|
|
448
|
+
- `antd` ^6.0.0
|
|
449
|
+
- `zustand` ^5.0.0
|
|
450
|
+
|
|
451
|
+
## 📝 License
|
|
452
|
+
|
|
453
|
+
MIT
|
|
454
|
+
|
|
455
|
+
## 👨💻 Author
|
|
456
|
+
|
|
457
|
+
leafront (leafront@126.com)
|
|
458
|
+
|
|
459
|
+
## 🔗 相关链接
|
|
460
|
+
|
|
461
|
+
- [GitHub](https://github.com/base-stone/hooks)
|
|
462
|
+
- [NPM](https://www.npmjs.com/package/@basestone/hooks)
|
|
463
|
+
- [Claude Code Skill](./.claude/skills/README.md)
|
|
@@ -66,10 +66,6 @@ export declare interface ModalProps {
|
|
|
66
66
|
onCancel: () => void;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
declare type noop = (this: any, ...args: any[]) => any;
|
|
70
|
-
|
|
71
|
-
declare type PickFunction<T extends noop> = (this: ThisParameterType<T>, ...args: Parameters<T>) => ReturnType<T>;
|
|
72
|
-
|
|
73
69
|
declare type Placement = 'top' | 'bottom' | 'left' | 'right';
|
|
74
70
|
|
|
75
71
|
declare interface QueryOptions<K extends string, T = Record<string, any>> {
|
|
@@ -107,6 +103,8 @@ declare type QueryResult<K extends string, T = Record<string, any>> = {
|
|
|
107
103
|
refresh: (params?: Record<string, any> | undefined) => void;
|
|
108
104
|
} & {
|
|
109
105
|
[P in K]?: T;
|
|
106
|
+
} & {
|
|
107
|
+
[P in SetterKey<K>]: (data: T | ((prevData: T) => T)) => void;
|
|
110
108
|
};
|
|
111
109
|
|
|
112
110
|
declare interface RequestFn {
|
|
@@ -143,6 +141,8 @@ declare type SelectOptionsResult<K extends string, V extends string | number = s
|
|
|
143
141
|
[P in `${K}Map`]?: MapData<V>;
|
|
144
142
|
}>;
|
|
145
143
|
|
|
144
|
+
declare type SetterKey<K extends string> = `set${Capitalize<K>}`;
|
|
145
|
+
|
|
146
146
|
declare interface SuccessFn {
|
|
147
147
|
(data: Record<string, any>): void;
|
|
148
148
|
}
|
|
@@ -199,8 +199,6 @@ export declare function useCreateModal<const T extends Record<string, ModalConfi
|
|
|
199
199
|
|
|
200
200
|
export declare function useFormSubmit(requestFn: RequestFn, successFn: SuccessFn): FormSubmitResult;
|
|
201
201
|
|
|
202
|
-
export declare function useMemoizedFn<T extends noop>(fn: T): PickFunction<T>;
|
|
203
|
-
|
|
204
202
|
export declare function useRequestQuery<T = Record<string, any> | Record<string, any>[] | undefined, const K extends string = string>({ queryFn, params, dataType, dataKey, initialValue, transform, success }: QueryOptions<K, T>): QueryResult<K, T>;
|
|
205
203
|
|
|
206
204
|
export declare function useSelectOptions<V extends string | number = string | number, const K extends string = string>({ queryFn, params, dataKey, fieldNames, transform }: SelectConfig<K>): SelectOptionsResult<K, V>;
|
|
@@ -1,180 +1,180 @@
|
|
|
1
|
-
import { useRef as
|
|
1
|
+
import { useRef as _, useMemo as V, useState as h, useEffectEvent as j, useEffect as T, useId as W, useCallback as X } from "react";
|
|
2
2
|
import { Empty as J, App as K } from "antd";
|
|
3
3
|
import { create as ee } from "zustand";
|
|
4
|
-
var
|
|
4
|
+
var F = { exports: {} }, x = {};
|
|
5
5
|
var H;
|
|
6
6
|
function te() {
|
|
7
|
-
if (H) return
|
|
7
|
+
if (H) return x;
|
|
8
8
|
H = 1;
|
|
9
|
-
var r = /* @__PURE__ */ Symbol.for("react.transitional.element"),
|
|
10
|
-
function o(t,
|
|
9
|
+
var r = /* @__PURE__ */ Symbol.for("react.transitional.element"), a = /* @__PURE__ */ Symbol.for("react.fragment");
|
|
10
|
+
function o(t, s, n) {
|
|
11
11
|
var d = null;
|
|
12
|
-
if (n !== void 0 && (d = "" + n),
|
|
12
|
+
if (n !== void 0 && (d = "" + n), s.key !== void 0 && (d = "" + s.key), "key" in s) {
|
|
13
13
|
n = {};
|
|
14
|
-
for (var c in
|
|
15
|
-
c !== "key" && (n[c] =
|
|
16
|
-
} else n =
|
|
17
|
-
return
|
|
14
|
+
for (var c in s)
|
|
15
|
+
c !== "key" && (n[c] = s[c]);
|
|
16
|
+
} else n = s;
|
|
17
|
+
return s = n.ref, {
|
|
18
18
|
$$typeof: r,
|
|
19
19
|
type: t,
|
|
20
20
|
key: d,
|
|
21
|
-
ref:
|
|
21
|
+
ref: s !== void 0 ? s : null,
|
|
22
22
|
props: n
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
|
-
return
|
|
25
|
+
return x.Fragment = a, x.jsx = o, x.jsxs = o, x;
|
|
26
26
|
}
|
|
27
27
|
var I;
|
|
28
|
-
function
|
|
29
|
-
return I || (I = 1,
|
|
28
|
+
function se() {
|
|
29
|
+
return I || (I = 1, F.exports = te()), F.exports;
|
|
30
30
|
}
|
|
31
|
-
var
|
|
32
|
-
function
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
const o =
|
|
31
|
+
var oe = se();
|
|
32
|
+
function b(r) {
|
|
33
|
+
const a = _(r);
|
|
34
|
+
a.current = V(() => r, [r]);
|
|
35
|
+
const o = _(void 0);
|
|
36
36
|
return o.current || (o.current = function(...t) {
|
|
37
|
-
return
|
|
37
|
+
return a.current.apply(this, t);
|
|
38
38
|
}), o.current;
|
|
39
39
|
}
|
|
40
|
-
const
|
|
40
|
+
const P = {
|
|
41
41
|
sortField: ["orderType", "orderField"],
|
|
42
42
|
sortOrder: ["ASC", "DESC"],
|
|
43
43
|
pageSize: 10
|
|
44
44
|
};
|
|
45
45
|
function ie(r) {
|
|
46
|
-
Object.keys(r).forEach((
|
|
47
|
-
|
|
46
|
+
Object.keys(r).forEach((a) => {
|
|
47
|
+
P[a] = r[a];
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
50
|
function ce({
|
|
51
51
|
queryFn: r,
|
|
52
|
-
params:
|
|
52
|
+
params: a,
|
|
53
53
|
transform: o,
|
|
54
54
|
rowSelection: t
|
|
55
55
|
}) {
|
|
56
|
-
const
|
|
56
|
+
const s = P.pageSize, [n, d] = h({
|
|
57
57
|
pagination: {
|
|
58
58
|
showSizeChanger: !0,
|
|
59
59
|
showQuickJumper: !0,
|
|
60
60
|
total: 0,
|
|
61
|
-
pageSize:
|
|
61
|
+
pageSize: s,
|
|
62
62
|
current: 1
|
|
63
63
|
},
|
|
64
64
|
list: [],
|
|
65
65
|
queryParams: {
|
|
66
66
|
pageNo: 1,
|
|
67
|
-
pageSize:
|
|
68
|
-
...
|
|
67
|
+
pageSize: s,
|
|
68
|
+
...a
|
|
69
69
|
}
|
|
70
|
-
}), { pagination: c, list: f, queryParams: e } = n, { pageNo: u, pageSize: p } = e, [i, v] =
|
|
70
|
+
}), { pagination: c, list: f, queryParams: e } = n, { pageNo: u, pageSize: p } = e, [i, v] = h(!0), [g, y] = h([]), C = V(() => {
|
|
71
71
|
if (t)
|
|
72
72
|
return {
|
|
73
73
|
selectedRowKeys: g,
|
|
74
|
-
onChange: (l) =>
|
|
74
|
+
onChange: (l) => y(l)
|
|
75
75
|
};
|
|
76
|
-
}, [t, g]),
|
|
76
|
+
}, [t, g]), R = b(
|
|
77
77
|
(l) => `共 ${l} 条记录 第 ${u}/${Math.ceil(l / p)} 页 `
|
|
78
78
|
), m = async (l) => {
|
|
79
79
|
const { pageNo: L } = l;
|
|
80
80
|
v(!0);
|
|
81
|
-
const E = { ...
|
|
81
|
+
const E = { ...a, pageSize: p, ...l };
|
|
82
82
|
l.pageNo === void 0 && (E.pageNo = 1), l.pageSize === void 0 && (E.pageSize = p);
|
|
83
|
-
const { data:
|
|
84
|
-
t &&
|
|
85
|
-
list:
|
|
83
|
+
const { data: z } = await r(E), k = o ? o(z) : z, { list: N = [], totalCount: A = 0 } = k || {};
|
|
84
|
+
t && y([]), d({
|
|
85
|
+
list: N,
|
|
86
86
|
queryParams: E,
|
|
87
87
|
pagination: {
|
|
88
88
|
...c,
|
|
89
89
|
current: L,
|
|
90
90
|
pageSize: E.pageSize,
|
|
91
|
-
total:
|
|
91
|
+
total: A
|
|
92
92
|
}
|
|
93
93
|
}), v(!1);
|
|
94
|
-
},
|
|
94
|
+
}, M = j(() => {
|
|
95
95
|
m({ ...e, pageNo: 1 });
|
|
96
|
-
}),
|
|
96
|
+
}), $ = (l) => {
|
|
97
97
|
m({ ...e, ...l, pageNo: 1 });
|
|
98
|
-
},
|
|
98
|
+
}, O = (l) => {
|
|
99
99
|
m({ ...e, ...l });
|
|
100
|
-
},
|
|
100
|
+
}, S = (l) => {
|
|
101
101
|
m({ ...l, pageSize: p, pageNo: 1 });
|
|
102
|
-
},
|
|
103
|
-
const { action:
|
|
104
|
-
if (["paginate", "sort"].includes(
|
|
105
|
-
const { current:
|
|
102
|
+
}, D = (l, L, E, z) => {
|
|
103
|
+
const { action: k } = z;
|
|
104
|
+
if (["paginate", "sort"].includes(k)) {
|
|
105
|
+
const { current: N, pageSize: A } = l, { field: G, order: q } = E, [Q, Y] = P.sortField, [U, Z] = P.sortOrder, B = {
|
|
106
106
|
...e,
|
|
107
|
-
[Q]: q ? q === "ascend" ?
|
|
107
|
+
[Q]: q ? q === "ascend" ? U : Z : void 0,
|
|
108
108
|
[Y]: G,
|
|
109
|
-
pageNo:
|
|
110
|
-
pageSize:
|
|
109
|
+
pageNo: N,
|
|
110
|
+
pageSize: A
|
|
111
111
|
};
|
|
112
|
-
m(
|
|
112
|
+
m(B);
|
|
113
113
|
}
|
|
114
114
|
};
|
|
115
115
|
return T(() => {
|
|
116
|
-
|
|
116
|
+
M();
|
|
117
117
|
}, []), {
|
|
118
118
|
queryParams: e,
|
|
119
|
-
search:
|
|
120
|
-
refresh:
|
|
121
|
-
reset:
|
|
119
|
+
search: b($),
|
|
120
|
+
refresh: b(O),
|
|
121
|
+
reset: b(S),
|
|
122
122
|
selectedRowKeys: g,
|
|
123
123
|
tableProps: {
|
|
124
124
|
bordered: !0,
|
|
125
125
|
size: "middle",
|
|
126
126
|
sticky: !0,
|
|
127
|
-
rowSelection:
|
|
127
|
+
rowSelection: C,
|
|
128
128
|
loading: i,
|
|
129
129
|
dataSource: f,
|
|
130
|
-
pagination: { ...c, showTotal:
|
|
131
|
-
onChange:
|
|
130
|
+
pagination: { ...c, showTotal: R },
|
|
131
|
+
onChange: b(D),
|
|
132
132
|
locale: {
|
|
133
|
-
emptyText: i ? "" : /* @__PURE__ */
|
|
133
|
+
emptyText: i ? "" : /* @__PURE__ */ oe.jsx(J, { image: J.PRESENTED_IMAGE_SIMPLE })
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
};
|
|
137
137
|
}
|
|
138
|
-
const
|
|
138
|
+
const w = ee((r) => ({
|
|
139
139
|
modals: {},
|
|
140
|
-
toggleModal: (
|
|
141
|
-
const n = t.modals[
|
|
140
|
+
toggleModal: (a, o) => r((t) => {
|
|
141
|
+
const n = t.modals[a]?.visible || !1;
|
|
142
142
|
return {
|
|
143
143
|
modals: {
|
|
144
144
|
...t.modals,
|
|
145
|
-
[
|
|
145
|
+
[a]: {
|
|
146
146
|
visible: !n,
|
|
147
147
|
data: n ? {} : o || {}
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
};
|
|
151
151
|
}),
|
|
152
|
-
setModal: (
|
|
152
|
+
setModal: (a, o, t) => r((s) => ({
|
|
153
153
|
modals: {
|
|
154
|
-
...
|
|
155
|
-
[
|
|
154
|
+
...s.modals,
|
|
155
|
+
[a]: {
|
|
156
156
|
visible: o,
|
|
157
157
|
data: o ? t || {} : {}
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
})),
|
|
161
|
-
clearModals: (
|
|
161
|
+
clearModals: (a) => r((o) => {
|
|
162
162
|
const t = { ...o.modals };
|
|
163
|
-
return
|
|
164
|
-
delete t[
|
|
163
|
+
return a.forEach((s) => {
|
|
164
|
+
delete t[s];
|
|
165
165
|
}), { modals: t };
|
|
166
166
|
})
|
|
167
167
|
}));
|
|
168
168
|
function le(r) {
|
|
169
|
-
const
|
|
169
|
+
const a = w((e) => e.modals), o = w((e) => e.toggleModal), t = w((e) => e.setModal), s = w((e) => e.clearModals), n = W(), d = _([]), c = Object.keys(r);
|
|
170
170
|
T(() => (d.current = c.map(
|
|
171
171
|
(e) => `${n}-${e}`
|
|
172
172
|
), () => {
|
|
173
|
-
|
|
173
|
+
s(d.current);
|
|
174
174
|
}), []);
|
|
175
175
|
const f = {};
|
|
176
176
|
return c.forEach((e) => {
|
|
177
|
-
const u = `${n}-${e}`, p =
|
|
177
|
+
const u = `${n}-${e}`, p = a[u] ?? { visible: !1, data: {} }, i = r[e], v = typeof i.title == "function" ? i.title(p.data) : i.title;
|
|
178
178
|
f[`${e}Modal`] = {
|
|
179
179
|
visible: p.visible,
|
|
180
180
|
data: p.data,
|
|
@@ -208,26 +208,26 @@ function le(r) {
|
|
|
208
208
|
t(`${n}-${e}`, !1);
|
|
209
209
|
}, f;
|
|
210
210
|
}
|
|
211
|
-
function ue({ queryFn: r, params:
|
|
212
|
-
const [n, d] =
|
|
211
|
+
function ue({ queryFn: r, params: a, dataKey: o, fieldNames: t, transform: s }) {
|
|
212
|
+
const [n, d] = h({
|
|
213
213
|
list: [],
|
|
214
214
|
mapData: /* @__PURE__ */ new Map()
|
|
215
|
-
}), [c, f] =
|
|
215
|
+
}), [c, f] = h(!0), e = async () => {
|
|
216
216
|
f(!0);
|
|
217
|
-
const { data: g, status:
|
|
218
|
-
if (
|
|
219
|
-
const
|
|
220
|
-
const
|
|
221
|
-
return
|
|
222
|
-
label:
|
|
223
|
-
value:
|
|
224
|
-
data:
|
|
217
|
+
const { data: g, status: y } = await r(a);
|
|
218
|
+
if (y === "success") {
|
|
219
|
+
const R = (s ? s(g) : g) || [], { label: m, value: M } = t, $ = /* @__PURE__ */ new Map([]), O = R.map((S) => {
|
|
220
|
+
const D = S[M];
|
|
221
|
+
return $.set(D, S[m]), {
|
|
222
|
+
label: S[m],
|
|
223
|
+
value: D,
|
|
224
|
+
data: S
|
|
225
225
|
};
|
|
226
226
|
});
|
|
227
|
-
d((
|
|
227
|
+
d((S) => ({ ...S, list: O, mapData: $ }));
|
|
228
228
|
}
|
|
229
229
|
f(!1);
|
|
230
|
-
}, u =
|
|
230
|
+
}, u = j(e), p = b(() => {
|
|
231
231
|
e();
|
|
232
232
|
});
|
|
233
233
|
T(() => {
|
|
@@ -241,16 +241,16 @@ function ue({ queryFn: r, params: s, dataKey: o, fieldNames: t, transform: a })
|
|
|
241
241
|
[`${o}Map`]: v
|
|
242
242
|
};
|
|
243
243
|
}
|
|
244
|
-
function de(r,
|
|
245
|
-
const [o, t] =
|
|
244
|
+
function de(r, a) {
|
|
245
|
+
const [o, t] = h(!1), { message: s } = K.useApp(), n = X(async (d) => {
|
|
246
246
|
try {
|
|
247
247
|
t(!0);
|
|
248
248
|
const c = await r(d), { status: f, info: e } = c;
|
|
249
|
-
f == "success" && (
|
|
249
|
+
f == "success" && (a(c), s.success(e));
|
|
250
250
|
} catch {
|
|
251
251
|
}
|
|
252
252
|
t(!1);
|
|
253
|
-
}, [r,
|
|
253
|
+
}, [r, a, s]);
|
|
254
254
|
return {
|
|
255
255
|
loading: o,
|
|
256
256
|
submit: n
|
|
@@ -258,30 +258,31 @@ function de(r, s) {
|
|
|
258
258
|
}
|
|
259
259
|
function pe({
|
|
260
260
|
queryFn: r,
|
|
261
|
-
params:
|
|
261
|
+
params: a,
|
|
262
262
|
dataType: o,
|
|
263
263
|
dataKey: t,
|
|
264
|
-
initialValue:
|
|
264
|
+
initialValue: s,
|
|
265
265
|
transform: n,
|
|
266
266
|
success: d
|
|
267
267
|
}) {
|
|
268
|
-
const c =
|
|
268
|
+
const c = s || (o === "Array" ? [] : /* @__PURE__ */ Object.create({})), [f, e] = h(c), [u, p] = h(!0), i = async (C) => {
|
|
269
269
|
p(!0);
|
|
270
|
-
const { data:
|
|
271
|
-
if (
|
|
272
|
-
const
|
|
273
|
-
d && d(
|
|
270
|
+
const { data: R, status: m } = await r(C ?? a), M = R === null ? o === "Array" ? [] : /* @__PURE__ */ Object.create({}) : R;
|
|
271
|
+
if (m === "success") {
|
|
272
|
+
const $ = n ? n(M) : M;
|
|
273
|
+
d && d(M), e($);
|
|
274
274
|
}
|
|
275
275
|
p(!1);
|
|
276
|
-
}, v =
|
|
276
|
+
}, v = j(i);
|
|
277
277
|
T(() => {
|
|
278
278
|
v();
|
|
279
279
|
}, []);
|
|
280
|
-
const g =
|
|
281
|
-
i(
|
|
282
|
-
})
|
|
280
|
+
const g = b((C) => {
|
|
281
|
+
i(C);
|
|
282
|
+
}), y = `set${t.charAt(0).toUpperCase()}${t.slice(1)}`;
|
|
283
283
|
return {
|
|
284
284
|
[t]: f,
|
|
285
|
+
[y]: e,
|
|
285
286
|
loading: u,
|
|
286
287
|
refresh: g
|
|
287
288
|
};
|
|
@@ -290,7 +291,6 @@ export {
|
|
|
290
291
|
ie as configureTableOption,
|
|
291
292
|
le as useCreateModal,
|
|
292
293
|
de as useFormSubmit,
|
|
293
|
-
y as useMemoizedFn,
|
|
294
294
|
pe as useRequestQuery,
|
|
295
295
|
ue as useSelectOptions,
|
|
296
296
|
ce as useTableList
|