@mtn-ui-z/utils 0.0.1
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 +161 -0
- package/package.json +23 -0
- package/src/common.d.ts +3 -0
- package/src/common.ts +16 -0
- package/src/date.ts +34 -0
- package/src/dict.ts +193 -0
- package/src/dom.d.ts +8 -0
- package/src/dom.ts +20 -0
- package/src/function.d.ts +1 -0
- package/src/function.ts +9 -0
- package/src/index.d.ts +36 -0
- package/src/index.ts +61 -0
- package/src/interaction.d.ts +1 -0
- package/src/interaction.ts +10 -0
- package/src/media.d.ts +6 -0
- package/src/media.ts +11 -0
- package/src/modalRegistry.ts +37 -0
- package/src/permission.d.ts +27 -0
- package/src/permission.ts +165 -0
- package/src/request-types.ts +57 -0
- package/src/request.ts +178 -0
- package/src/state.d.ts +6 -0
- package/src/state.ts +11 -0
- package/src/storage.ts +143 -0
- package/src/theme.d.ts +107 -0
- package/src/theme.ts +502 -0
- package/src/types.d.ts +6 -0
- package/src/types.ts +11 -0
- package/src/useModal.ts +110 -0
- package/src/useTable.ts +307 -0
package/src/useTable.ts
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @Author: liaokt
|
|
3
|
+
* @Description: 表格状态管理 Hook - 仿 ahooks useAntdTable 风格
|
|
4
|
+
* @Date: 2025-09-25 10:20:00
|
|
5
|
+
* @LastEditors: liaokt
|
|
6
|
+
* @LastEditTime: 2025-12-26 16:56:24
|
|
7
|
+
*/
|
|
8
|
+
import { ref, reactive, watch, type Ref } from 'vue'
|
|
9
|
+
|
|
10
|
+
// 数据类型定义
|
|
11
|
+
export interface Data {
|
|
12
|
+
total: number
|
|
13
|
+
list: any[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 支持两种函数签名:
|
|
17
|
+
// 1. 标准格式:(pagination, searchParams) => Promise<Data>
|
|
18
|
+
// 2. 简化格式:(params) => Promise<any> - 会自动转换数据格式
|
|
19
|
+
type ServiceFunction<TData extends Data> =
|
|
20
|
+
| ((
|
|
21
|
+
pagination: { current: number; page_size: number },
|
|
22
|
+
searchParams: Record<string, any>
|
|
23
|
+
) => Promise<TData>)
|
|
24
|
+
| ((params?: Record<string, any>) => Promise<any>)
|
|
25
|
+
|
|
26
|
+
export interface UseTableOptions {
|
|
27
|
+
/** 默认参数 */
|
|
28
|
+
defaultParams?: any
|
|
29
|
+
/** 默认页面大小 */
|
|
30
|
+
defaultPageSize?: number
|
|
31
|
+
/** 刷新依赖 */
|
|
32
|
+
refreshDeps?: any[]
|
|
33
|
+
/** 是否立即请求 */
|
|
34
|
+
manual?: boolean
|
|
35
|
+
/** 搜索参数格式化函数 */
|
|
36
|
+
searchFormatter?: (params: any) => any
|
|
37
|
+
/** 错误处理函数 */
|
|
38
|
+
onError?: (error: Error) => void
|
|
39
|
+
/** 成功回调 */
|
|
40
|
+
onSuccess?: (data: any) => void
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface UseTableResult<TData extends Data> {
|
|
44
|
+
/** 表格属性 */
|
|
45
|
+
tableProps: {
|
|
46
|
+
dataSource: TData['list']
|
|
47
|
+
loading: boolean
|
|
48
|
+
onChange: (pagination: any, filters?: any, sorter?: any, extra?: any) => void
|
|
49
|
+
pagination: {
|
|
50
|
+
current: number
|
|
51
|
+
pageSize: number
|
|
52
|
+
total: number
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** 搜索功能 */
|
|
56
|
+
search: {
|
|
57
|
+
submit: (params: Record<string, any>) => void
|
|
58
|
+
reset: () => void
|
|
59
|
+
}
|
|
60
|
+
/** 数据源 */
|
|
61
|
+
dataSource: Ref<TData['list']>
|
|
62
|
+
/** 加载状态 */
|
|
63
|
+
loading: Ref<boolean>
|
|
64
|
+
/** 分页状态 */
|
|
65
|
+
pagination: Ref<{
|
|
66
|
+
current: number
|
|
67
|
+
page_size: number
|
|
68
|
+
total: number
|
|
69
|
+
}>
|
|
70
|
+
/** 选中的行键 */
|
|
71
|
+
selectedRowKeys: Ref<string[]>
|
|
72
|
+
/** 选中的行数据 */
|
|
73
|
+
selectedRows: Ref<any[]>
|
|
74
|
+
/** 刷新 */
|
|
75
|
+
refresh: () => Promise<void>
|
|
76
|
+
/** 重新加载 */
|
|
77
|
+
reload: () => Promise<void>
|
|
78
|
+
/** 重置 */
|
|
79
|
+
reset: () => void
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function useTable<TData extends Data>(
|
|
83
|
+
service: ServiceFunction<TData>,
|
|
84
|
+
options: UseTableOptions = {}
|
|
85
|
+
): UseTableResult<TData> {
|
|
86
|
+
const {
|
|
87
|
+
defaultParams,
|
|
88
|
+
defaultPageSize = 10,
|
|
89
|
+
refreshDeps = [],
|
|
90
|
+
manual = false,
|
|
91
|
+
searchFormatter,
|
|
92
|
+
onError,
|
|
93
|
+
onSuccess
|
|
94
|
+
} = options
|
|
95
|
+
|
|
96
|
+
// 状态
|
|
97
|
+
const dataSource = ref<any[]>([]) as Ref<TData['list']>
|
|
98
|
+
const loading = ref(false)
|
|
99
|
+
const selectedRowKeys = ref<string[]>([])
|
|
100
|
+
const selectedRows = ref<any[]>([])
|
|
101
|
+
|
|
102
|
+
// 分页状态
|
|
103
|
+
const pagination = ref({
|
|
104
|
+
current: 1,
|
|
105
|
+
page_size: defaultPageSize,
|
|
106
|
+
total: 0
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
// 搜索状态
|
|
110
|
+
const searchParams = ref<any>(defaultParams || {})
|
|
111
|
+
|
|
112
|
+
// 表格 onChange(提取为顶层函数,模板中可直接绑定)
|
|
113
|
+
const handleTableChange = (paginationParams: any) => {
|
|
114
|
+
pagination.value.current = paginationParams.current
|
|
115
|
+
pagination.value.page_size = paginationParams.pageSize
|
|
116
|
+
run()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 表格属性
|
|
120
|
+
const tableProps = reactive({
|
|
121
|
+
get dataSource() {
|
|
122
|
+
return dataSource.value
|
|
123
|
+
},
|
|
124
|
+
get loading() {
|
|
125
|
+
return loading.value
|
|
126
|
+
},
|
|
127
|
+
onChange: handleTableChange,
|
|
128
|
+
get pagination() {
|
|
129
|
+
return {
|
|
130
|
+
current: pagination.value.current,
|
|
131
|
+
pageSize: pagination.value.page_size,
|
|
132
|
+
total: pagination.value.total,
|
|
133
|
+
showSizeChanger: true,
|
|
134
|
+
showTotal: (t: number) => `共 ${t} 条`
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
// 搜索功能
|
|
140
|
+
const search = {
|
|
141
|
+
submit: (params: Record<string, any>) => {
|
|
142
|
+
pagination.value.current = 1
|
|
143
|
+
searchParams.value = params
|
|
144
|
+
run()
|
|
145
|
+
},
|
|
146
|
+
reset: () => {
|
|
147
|
+
searchParams.value = {}
|
|
148
|
+
pagination.value.current = 1
|
|
149
|
+
run()
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 请求数据
|
|
154
|
+
const run = async () => {
|
|
155
|
+
loading.value = true
|
|
156
|
+
try {
|
|
157
|
+
// 格式化搜索参数
|
|
158
|
+
const formattedSearchParams = searchFormatter
|
|
159
|
+
? searchFormatter(searchParams.value)
|
|
160
|
+
: searchParams.value
|
|
161
|
+
|
|
162
|
+
// 构建请求参数
|
|
163
|
+
const paginationParams = {
|
|
164
|
+
current: pagination.value.current,
|
|
165
|
+
page_size: pagination.value.page_size
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 检测函数签名:如果函数接受单个参数,则合并参数
|
|
169
|
+
const params = {
|
|
170
|
+
page: paginationParams.current,
|
|
171
|
+
page_size: paginationParams.page_size,
|
|
172
|
+
...formattedSearchParams
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// 调用服务函数
|
|
176
|
+
let result: any
|
|
177
|
+
if (service.length === 0 || service.length === 1) {
|
|
178
|
+
// 简化格式:接受单个参数对象
|
|
179
|
+
result = await (service as (params?: Record<string, any>) => Promise<any>)(params)
|
|
180
|
+
} else {
|
|
181
|
+
// 标准格式:接受两个参数
|
|
182
|
+
result = await (service as (pagination: any, searchParams: any) => Promise<TData>)(
|
|
183
|
+
paginationParams,
|
|
184
|
+
formattedSearchParams
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 处理返回数据格式
|
|
189
|
+
let finalResult: TData
|
|
190
|
+
if (result && typeof result === 'object') {
|
|
191
|
+
// 如果返回的是 { list, total } 格式,直接使用
|
|
192
|
+
if ('list' in result && 'total' in result) {
|
|
193
|
+
finalResult = result as TData
|
|
194
|
+
}
|
|
195
|
+
// 如果返回 { data: [], total } 这样的结构
|
|
196
|
+
else if (Array.isArray((result as any).data) && 'total' in result) {
|
|
197
|
+
finalResult = {
|
|
198
|
+
list: (result as any).data,
|
|
199
|
+
total: (result as any).total ?? (result as any).data.length
|
|
200
|
+
} as TData
|
|
201
|
+
}
|
|
202
|
+
// 如果返回的是 { code, data } 格式(API 响应格式),需要转换
|
|
203
|
+
else if ('data' in result && 'code' in result) {
|
|
204
|
+
const data = result.data
|
|
205
|
+
// 如果 data 是数组
|
|
206
|
+
if (Array.isArray(data)) {
|
|
207
|
+
finalResult = {
|
|
208
|
+
list: data,
|
|
209
|
+
total: data.length
|
|
210
|
+
} as TData
|
|
211
|
+
}
|
|
212
|
+
// 如果 data 是分页对象 { list, total }
|
|
213
|
+
else if (data && typeof data === 'object' && 'list' in data && 'total' in data) {
|
|
214
|
+
finalResult = {
|
|
215
|
+
list: data.list || [],
|
|
216
|
+
total: data.total || 0
|
|
217
|
+
} as TData
|
|
218
|
+
}
|
|
219
|
+
// 如果 data 是分页对象 { results, count }
|
|
220
|
+
else if (data && typeof data === 'object' && 'results' in data && 'count' in data) {
|
|
221
|
+
finalResult = {
|
|
222
|
+
list: (data.results as any[]) || [],
|
|
223
|
+
total: (data.count as number) || 0
|
|
224
|
+
} as TData
|
|
225
|
+
}
|
|
226
|
+
// 其他情况,默认空列表
|
|
227
|
+
else {
|
|
228
|
+
finalResult = {
|
|
229
|
+
list: [],
|
|
230
|
+
total: 0
|
|
231
|
+
} as unknown as TData
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// 其他格式,尝试直接使用
|
|
235
|
+
else {
|
|
236
|
+
finalResult = result as TData
|
|
237
|
+
}
|
|
238
|
+
} else {
|
|
239
|
+
// 非对象类型,返回空列表
|
|
240
|
+
finalResult = {
|
|
241
|
+
list: [],
|
|
242
|
+
total: 0
|
|
243
|
+
} as unknown as TData
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
dataSource.value = finalResult.list as TData['list']
|
|
247
|
+
pagination.value.total = finalResult.total
|
|
248
|
+
|
|
249
|
+
// 成功回调
|
|
250
|
+
onSuccess?.(finalResult)
|
|
251
|
+
} catch (error) {
|
|
252
|
+
console.error('请求数据失败:', error)
|
|
253
|
+
// 错误处理回调
|
|
254
|
+
onError?.(error as Error)
|
|
255
|
+
} finally {
|
|
256
|
+
loading.value = false
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 刷新
|
|
261
|
+
const refresh = async () => {
|
|
262
|
+
await run()
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// 重新加载
|
|
266
|
+
const reload = async () => {
|
|
267
|
+
pagination.value.current = 1
|
|
268
|
+
await run()
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// 重置
|
|
272
|
+
const reset = () => {
|
|
273
|
+
pagination.value.current = 1
|
|
274
|
+
pagination.value.page_size = defaultPageSize
|
|
275
|
+
dataSource.value = [] as TData['list']
|
|
276
|
+
selectedRowKeys.value = []
|
|
277
|
+
selectedRows.value = []
|
|
278
|
+
searchParams.value = {}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// 监听刷新依赖
|
|
282
|
+
watch(
|
|
283
|
+
refreshDeps,
|
|
284
|
+
() => {
|
|
285
|
+
run()
|
|
286
|
+
},
|
|
287
|
+
{ immediate: false }
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
// 立即请求
|
|
291
|
+
if (!manual) {
|
|
292
|
+
run()
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
tableProps,
|
|
297
|
+
search,
|
|
298
|
+
dataSource,
|
|
299
|
+
loading,
|
|
300
|
+
pagination,
|
|
301
|
+
selectedRowKeys,
|
|
302
|
+
selectedRows,
|
|
303
|
+
refresh,
|
|
304
|
+
reload,
|
|
305
|
+
reset
|
|
306
|
+
}
|
|
307
|
+
}
|