@ithinkdt/page 4.0.18 → 4.0.19
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 +545 -0
- package/package.json +8 -8
- package/src/form.d.ts +20 -15
- package/src/form.js +13 -7
- package/src/plugin.d.ts +6 -1
- package/src/table.d.ts +1 -1
- package/src/table.js +7 -4
package/README.md
CHANGED
|
@@ -1 +1,546 @@
|
|
|
1
1
|
# @ithinkdt/page
|
|
2
|
+
|
|
3
|
+
## 许可证
|
|
4
|
+
|
|
5
|
+
MIT
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm i @ithinkdt/page
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
> 需要您自行安装依赖 `vue@3` 与 `vue-router@4`。
|
|
14
|
+
|
|
15
|
+
## 介绍
|
|
16
|
+
|
|
17
|
+
`@ithinkdt/page` 提供 iThinkDT 页面开发的核心组合式 API,包括:
|
|
18
|
+
|
|
19
|
+
- 数据源管理(远程分页/本地数据)
|
|
20
|
+
- 前端分页
|
|
21
|
+
- 表单管理(查询筛选、编辑表单、表单弹窗)
|
|
22
|
+
- 表格列定义与自定义列
|
|
23
|
+
- CRUD 操作(新增、编辑、查看、删除)
|
|
24
|
+
- 描述详情展示
|
|
25
|
+
- 模态框(对话框/抽屉)
|
|
26
|
+
- 表单校验规则
|
|
27
|
+
|
|
28
|
+
## 初始化
|
|
29
|
+
|
|
30
|
+
### 注册插件
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createApp } from 'vue'
|
|
34
|
+
import pagePlugin from '@ithinkdt/page'
|
|
35
|
+
|
|
36
|
+
const app = createApp(App)
|
|
37
|
+
|
|
38
|
+
app.use(pagePlugin, {
|
|
39
|
+
i18n,
|
|
40
|
+
getConfirmRenderer: () => renderConfirm,
|
|
41
|
+
getModalRenderer: () => renderModal,
|
|
42
|
+
getFormRenderer: () => renderForm,
|
|
43
|
+
getFormItemRenderer: {
|
|
44
|
+
text: () => renderTextInput,
|
|
45
|
+
},
|
|
46
|
+
getDescriptionRenderer: {
|
|
47
|
+
text: () => (value) => value,
|
|
48
|
+
},
|
|
49
|
+
getTableActionsRenderer: () => renderTableActions,
|
|
50
|
+
defaultPageSize: 20,
|
|
51
|
+
defaultFilterCached: true,
|
|
52
|
+
})
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 组合式 API
|
|
56
|
+
|
|
57
|
+
### `useDs` 数据源
|
|
58
|
+
|
|
59
|
+
用于管理远程分页数据或本地数据列表,支持增删改操作:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { useDs } from '@ithinkdt/page'
|
|
63
|
+
import { userApi } from '@/api/user'
|
|
64
|
+
|
|
65
|
+
const ds = useDs(
|
|
66
|
+
async ({ currentPage, pageSize, sortField, sortOrder }, filter) => {
|
|
67
|
+
const res = await userApi.page({ currentPage, pageSize, sortField, sortOrder, filter })
|
|
68
|
+
return res
|
|
69
|
+
},
|
|
70
|
+
{ pagination: 'remote', defaultPageSize: 20 },
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
// 刷新数据
|
|
74
|
+
ds.pull({ currentPage: 1, pageSize: 20 })
|
|
75
|
+
|
|
76
|
+
// 本地插入一条
|
|
77
|
+
ds.insert({ id: 'new', name: '张三' })
|
|
78
|
+
|
|
79
|
+
// 本地更新一条
|
|
80
|
+
ds.set('id-xxx', { name: '李四' })
|
|
81
|
+
|
|
82
|
+
// 本地删除一条
|
|
83
|
+
ds.remove('id-xxx')
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `useFilterHelper` 查询筛选表单
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { useFilterHelper } from '@ithinkdt/page'
|
|
90
|
+
|
|
91
|
+
const { model, items, reset, validate } = useFilterHelper(
|
|
92
|
+
({ it, model, validate }) => [
|
|
93
|
+
it('name', '用户名', 'text', { placeholder: '请输入用户名' }),
|
|
94
|
+
it('status', '状态', 'select', { selectProps: { options: statusOptions } }),
|
|
95
|
+
],
|
|
96
|
+
{ cached: true },
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `useFormHelper` 表单管理
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { useFormHelper } from '@ithinkdt/page'
|
|
104
|
+
|
|
105
|
+
const { model, items, validate } = useFormHelper(
|
|
106
|
+
({ it, model, validate, group, reset }) => [
|
|
107
|
+
it('name', '名称', 'text', { required: true }),
|
|
108
|
+
it('email', '邮箱', 'text', { rule: email('请输入有效邮箱') }),
|
|
109
|
+
group(computed(() => model.country === 'China'), [
|
|
110
|
+
it('phone', '手机号', 'text'),
|
|
111
|
+
]),
|
|
112
|
+
],
|
|
113
|
+
{
|
|
114
|
+
initial: { name: '' },
|
|
115
|
+
onChange(name, value) {
|
|
116
|
+
console.log(`${name} changed:`, value)
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
// 校验
|
|
122
|
+
const [valid] = await validate()
|
|
123
|
+
if (valid) {
|
|
124
|
+
await submit(model)
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### `useFormModal` 表单弹窗
|
|
129
|
+
|
|
130
|
+
将表单放入模态框中展示,常用于编辑场景:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
import { useFormModal } from '@ithinkdt/page'
|
|
134
|
+
|
|
135
|
+
const { open, close } = useFormModal({
|
|
136
|
+
title: '编辑用户',
|
|
137
|
+
type: 'dialog',
|
|
138
|
+
width: 600,
|
|
139
|
+
items: ({ it, model }) => [
|
|
140
|
+
it('name', '名称', 'text', { required: true }),
|
|
141
|
+
],
|
|
142
|
+
onSubmit: async (data) => {
|
|
143
|
+
await userApi.save(data)
|
|
144
|
+
},
|
|
145
|
+
initial: { name: '' },
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
// 打开弹窗,传入初始数据
|
|
149
|
+
await open({ id: '1', name: '张三' })
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### `useSimpleCrud` CRUD 操作
|
|
153
|
+
|
|
154
|
+
封装新增、编辑、查看、删除的标准流程:
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
import { useSimpleCrud } from '@ithinkdt/page'
|
|
158
|
+
|
|
159
|
+
const { onAdd, onEdit, onView, onDel } = useSimpleCrud({
|
|
160
|
+
get: id => userApi.get(id),
|
|
161
|
+
save: data => userApi.save(data),
|
|
162
|
+
delete: id => userApi.delete(id),
|
|
163
|
+
// 增删改查用统一的表单
|
|
164
|
+
items: ({ it }) => [
|
|
165
|
+
it('name', '名称', 'text', { required: true }),
|
|
166
|
+
it('status', '状态', 'select'),
|
|
167
|
+
it('name', '名称', 'text'),
|
|
168
|
+
it('email', '邮箱', 'text'),
|
|
169
|
+
],
|
|
170
|
+
// 差别较大的时候,可以分开定义
|
|
171
|
+
createItems: ({ it }) => [
|
|
172
|
+
it('name', '名称', 'text', { required: true }),
|
|
173
|
+
],
|
|
174
|
+
editItems: ({ it, model }) => [
|
|
175
|
+
it('name', '名称', 'text', { required: true }),
|
|
176
|
+
it('status', '状态', 'select'),
|
|
177
|
+
],
|
|
178
|
+
viewItems: ({ it }) => [
|
|
179
|
+
it('name', '名称', 'text'),
|
|
180
|
+
it('email', '邮箱', 'text'),
|
|
181
|
+
],
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
// 新增
|
|
185
|
+
await onAdd({ name: '张三' })
|
|
186
|
+
|
|
187
|
+
// 编辑
|
|
188
|
+
await onEdit('id-xxx')
|
|
189
|
+
|
|
190
|
+
// 查看
|
|
191
|
+
await onView('id-xxx')
|
|
192
|
+
|
|
193
|
+
// 删除(带确认弹窗)
|
|
194
|
+
await onDel('id-xxx')
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### `useDeleteHelper` 删除确认
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { useDeleteHelper } from '@ithinkdt/page'
|
|
201
|
+
|
|
202
|
+
const { onDel } = useDeleteHelper({
|
|
203
|
+
delete: ids => Array.isArray(ids) ? userApi.deleteBatch(ids) : userApi.delete(id),
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
// 单个删除
|
|
207
|
+
await onDel('id-xxx')
|
|
208
|
+
|
|
209
|
+
// 批量删除
|
|
210
|
+
await onDel(['id-1', 'id-2'])
|
|
211
|
+
|
|
212
|
+
// 自定义提示
|
|
213
|
+
await onDel('id-xxx', '确认删除', '该操作不可撤销')
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### `useTableHelper` 表格列定义
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
import { useTableHelper, calcActionWidth } from '@ithinkdt/page'
|
|
220
|
+
|
|
221
|
+
const { columns, custom } = useTableHelper(
|
|
222
|
+
({ col, cols, group }) => [
|
|
223
|
+
col('index', '#', (_, __, i) => i + 1, { width: 60 }),
|
|
224
|
+
col('name', '用户名', { width: 120 }),
|
|
225
|
+
col('email', '邮箱', 'text', { ellipsis: true }),
|
|
226
|
+
col('status', '状态', { width: 100, render: v => v ? '启用' : '禁用' }),
|
|
227
|
+
cols('操作', [
|
|
228
|
+
col('$edit', '', (_, record) => h('Button', { onClick: () => onEdit(record) }, '编辑')),
|
|
229
|
+
col('$delete', '', (_, record) => h('Button', { onClick: () => onDel(record) }, '删除')),
|
|
230
|
+
], { fixed: 'right' }),
|
|
231
|
+
],
|
|
232
|
+
{
|
|
233
|
+
index: i => i + (params.currentPage - 1) * params.pageSize,
|
|
234
|
+
selectable: canSelect && (record) => record.status === 'selectable',
|
|
235
|
+
customizable: true,
|
|
236
|
+
actions: [
|
|
237
|
+
{ preset: 'edit', onClick: (record) => onEdit(record) },
|
|
238
|
+
{ preset: 'delete', onClick: (record) => onDel(record) },
|
|
239
|
+
],
|
|
240
|
+
},
|
|
241
|
+
)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### `useDescriptionsHelper` 描述详情
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
import { useDescriptionsHelper } from '@ithinkdt/page'
|
|
248
|
+
|
|
249
|
+
const { items, model, reset } = useDescriptionsHelper(
|
|
250
|
+
({ it, group }) => [
|
|
251
|
+
it('name', '用户名', 'text'),
|
|
252
|
+
it('email', '邮箱'),
|
|
253
|
+
it('status', '状态', (value) => value ? '启用' : '禁用'),
|
|
254
|
+
group('contact', '联系方式', [
|
|
255
|
+
it('phone', '手机号', 'text'),
|
|
256
|
+
it('address', '地址', 'text'),
|
|
257
|
+
]),
|
|
258
|
+
],
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
// 设置数据
|
|
262
|
+
reset({ name: '张三', email: 'zhangsan@example.com', phone: '13800000000' })
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### `useModal` 模态框
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
import { useModal, useModalRef } from '@ithinkdt/page'
|
|
269
|
+
|
|
270
|
+
const xxx = ref('123')
|
|
271
|
+
const modal = useModal({
|
|
272
|
+
type: 'drawer',
|
|
273
|
+
title: '编辑',
|
|
274
|
+
width: 600,
|
|
275
|
+
content: () => <MyForm xxx={xxx.value} />,
|
|
276
|
+
onConfirm: async () => {
|
|
277
|
+
await submit()
|
|
278
|
+
},
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
// 打开
|
|
282
|
+
await modal.open()
|
|
283
|
+
|
|
284
|
+
// 关闭
|
|
285
|
+
modal.close()
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### `useDataPagination` 前端分页
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
import { useDataPagination } from '@ithinkdt/page'
|
|
292
|
+
import { ref } from 'vue'
|
|
293
|
+
|
|
294
|
+
const allData = ref([...])
|
|
295
|
+
const { data, pagination, paginate } = useDataPagination(allData, { pageSize: 10 })
|
|
296
|
+
|
|
297
|
+
// data 为当前页数据,pagination 为分页状态
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## 校验规则
|
|
301
|
+
|
|
302
|
+
`@ithinkdt/page/rules` 提供常用的表单校验规则:
|
|
303
|
+
|
|
304
|
+
```ts
|
|
305
|
+
import { required, min, max, email, phone, url, idNo, chinese, noChinese } from '@ithinkdt/page/rules'
|
|
306
|
+
|
|
307
|
+
const rules = {
|
|
308
|
+
name: required('请输入名称'),
|
|
309
|
+
age: min(0, val => '年龄不能小于0'),
|
|
310
|
+
email: email('请输入有效邮箱'),
|
|
311
|
+
phone: phone('请输入有效手机号'),
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## API 参考
|
|
316
|
+
|
|
317
|
+
### `useDs(fetch, options?)`
|
|
318
|
+
|
|
319
|
+
| 参数 | 说明 |
|
|
320
|
+
|------|------|
|
|
321
|
+
| `fetch` | `(sortParams, filter) => Promise<{ total, records } \| T[]>`,数据获取函数 |
|
|
322
|
+
| `options.pagination` | `'remote'` 远程分页,`false` 本地数据 |
|
|
323
|
+
| `options.defaultPageSize` | 默认分页大小,默认 `10` |
|
|
324
|
+
| `options.keyField` | 主键字段名,默认 `'key'` |
|
|
325
|
+
| `options.defaultSortField` | 默认排序字段 |
|
|
326
|
+
| `options.defaultSortOrder` | 默认排序方向,`'asc'` / `'desc'` |
|
|
327
|
+
| `options.shallow` | 是否使用 `shallowReactive`,默认 `true` |
|
|
328
|
+
| `options.immediate` | 是否立即执行 fetch,默认 `false` |
|
|
329
|
+
| `options.resetOnFetch` | fetch 时是否先重置为空,默认 `false` |
|
|
330
|
+
|
|
331
|
+
| 属性/方法 | 说明 |
|
|
332
|
+
|-----------|------|
|
|
333
|
+
| `state` | 响应式数据(远程分页模式下含 `total` 与 `records`) |
|
|
334
|
+
| `loading` | 加载状态 |
|
|
335
|
+
| `error` | 错误信息 |
|
|
336
|
+
| `execute(...params)` | 执行 fetch 刷新数据 |
|
|
337
|
+
| `get(key)` | 根据主键获取数据项 |
|
|
338
|
+
| `insert(item, index?)` | 插入数据项 |
|
|
339
|
+
| `set(key, item)` | 更新数据项 |
|
|
340
|
+
| `remove(key)` | 删除数据项 |
|
|
341
|
+
|
|
342
|
+
### `useFilterHelper(items, options?)`
|
|
343
|
+
|
|
344
|
+
| 参数 | 说明 |
|
|
345
|
+
|------|------|
|
|
346
|
+
| `items` | `(helper) => FormItemOptions[]`,表单项定义函数 |
|
|
347
|
+
| `options.initial` | 表单初始值 |
|
|
348
|
+
| `options.rules` | 校验规则对象或函数 |
|
|
349
|
+
| `options.onChange` | `(name, value) => void`,字段变更回调 |
|
|
350
|
+
| `options.cached` | 是否缓存筛选表单,默认取插件 `defaultFilterCached` |
|
|
351
|
+
| `options.cacheVersion` | 缓存版本号,默认 `1` |
|
|
352
|
+
| `options.customizable` | 是否允许自定义筛选项显隐 |
|
|
353
|
+
|
|
354
|
+
| 属性/方法 | 说明 |
|
|
355
|
+
|-----------|------|
|
|
356
|
+
| `model` | 响应式表单数据 |
|
|
357
|
+
| `items` | 响应式表单项列表 |
|
|
358
|
+
| `reset(initial?)` | 重置表单 |
|
|
359
|
+
| `validate()` | 校验表单 |
|
|
360
|
+
| `invalid` | 是否校验不通过 |
|
|
361
|
+
| `validation` | 校验结果详情 |
|
|
362
|
+
| `custom(modify)` | 自定义筛选项显隐/排序 |
|
|
363
|
+
|
|
364
|
+
### `useFormHelper(items, options?)`
|
|
365
|
+
|
|
366
|
+
| 参数 | 说明 |
|
|
367
|
+
|------|------|
|
|
368
|
+
| `items` | `(helper) => FormItemOptions[]`,表单项定义函数 |
|
|
369
|
+
| `options.initial` | 表单初始值 |
|
|
370
|
+
| `options.rules` | 校验规则对象或函数 |
|
|
371
|
+
| `options.onChange` | `(name, value) => void`,字段变更回调 |
|
|
372
|
+
|
|
373
|
+
| 属性/方法 | 说明 |
|
|
374
|
+
|-----------|------|
|
|
375
|
+
| `model` | 响应式表单数据 |
|
|
376
|
+
| `items` | 响应式表单项列表 |
|
|
377
|
+
| `reset(initial?)` | 重置表单(`overwrite=true` 覆盖,`reinit=true` 同时重建表单项) |
|
|
378
|
+
| `reinit()` | 重新初始化表单项 |
|
|
379
|
+
| `validate()` | 校验表单 |
|
|
380
|
+
| `invalid` | 是否校验不通过 |
|
|
381
|
+
| `validation` | 校验结果详情 |
|
|
382
|
+
| `beforeSubmit(prop)` | 提交前校验(支持单字段或数组) |
|
|
383
|
+
|
|
384
|
+
### `useFormModal(options)`
|
|
385
|
+
|
|
386
|
+
| 参数 | 说明 |
|
|
387
|
+
|------|------|
|
|
388
|
+
| `options.title` | 弹窗标题 |
|
|
389
|
+
| `options.type` | `'dialog'` / `'drawer'`,弹窗类型 |
|
|
390
|
+
| `options.width` | 弹窗宽度 |
|
|
391
|
+
| `options.items` | `(helper) => FormItemOptions[]`,表单项定义函数 |
|
|
392
|
+
| `options.initial` | 表单初始值 |
|
|
393
|
+
| `options.rules` | 校验规则 |
|
|
394
|
+
| `options.onSubmit` | `(data) => Promise<void>`,提交回调 |
|
|
395
|
+
| `options.loading` | 加载状态 |
|
|
396
|
+
| `options.readonly` | 是否只读 |
|
|
397
|
+
| `options.maskClosable` | 点击遮罩是否关闭,默认 `false` |
|
|
398
|
+
| `options.closable` | 是否显示关闭按钮,默认 `true` |
|
|
399
|
+
|
|
400
|
+
| 属性/方法 | 说明 |
|
|
401
|
+
|-----------|------|
|
|
402
|
+
| `open(initial?, title?)` | 打开表单弹窗 |
|
|
403
|
+
| `close()` | 关闭弹窗 |
|
|
404
|
+
|
|
405
|
+
### `useSimpleCrud(options)`
|
|
406
|
+
|
|
407
|
+
| 参数 | 说明 |
|
|
408
|
+
|------|------|
|
|
409
|
+
| `options.get` | `(id) => Promise<Entity>`,获取详情 |
|
|
410
|
+
| `options.post` / `save` | `(data) => Promise<Entity>`,新增 |
|
|
411
|
+
| `options.put` | `(data) => Promise<Entity>`,编辑 |
|
|
412
|
+
| `options.delete` | `(id) => Promise<void>`,删除 |
|
|
413
|
+
| `options.createItems` | 新建表单的表单项定义函数 |
|
|
414
|
+
| `options.editItems` | 编辑表单的表单项定义函数 |
|
|
415
|
+
| `options.viewItems` | 查看表单的表单项定义函数 |
|
|
416
|
+
| `options.items` / `formItems` | 新建和编辑共用的表单项定义函数 |
|
|
417
|
+
| `options.width` | 弹窗宽度,可按 type 返回不同宽度 |
|
|
418
|
+
| `options.cols` | 表单列数,可按 type 返回不同列数 |
|
|
419
|
+
| `options.modalType` | `'dialog'` / `'drawer'`,可按 type 返回不同类型 |
|
|
420
|
+
| `options.deleteButtonText` | 删除按钮文案 |
|
|
421
|
+
|
|
422
|
+
| 方法 | 说明 |
|
|
423
|
+
|------|------|
|
|
424
|
+
| `onAdd(initial?, title?)` | 新增 |
|
|
425
|
+
| `onEdit(dataOrKey, title?)` | 编辑 |
|
|
426
|
+
| `onView(dataOrKey, title?)` | 查看 |
|
|
427
|
+
| `onDel(keyOrKeys, title?, tip?)` | 删除 |
|
|
428
|
+
|
|
429
|
+
### `useDeleteHelper(options)`
|
|
430
|
+
|
|
431
|
+
| 参数 | 说明 |
|
|
432
|
+
|------|------|
|
|
433
|
+
| `options.delete` | `(ids) => Promise<void>`,删除请求函数 |
|
|
434
|
+
| `options.keyField` | 主键字段名,默认使用插件注入的 `keyField` |
|
|
435
|
+
| `options.deleteButtonText` | 删除按钮文案 |
|
|
436
|
+
| `options.renderDelete` | 自定义删除确认内容渲染函数 |
|
|
437
|
+
|
|
438
|
+
| 方法 | 说明 |
|
|
439
|
+
|------|------|
|
|
440
|
+
| `onDel(keyOrKeys, title?, tip?)` | 删除(带确认弹窗) |
|
|
441
|
+
|
|
442
|
+
### `useTableHelper(columns, options?)`
|
|
443
|
+
|
|
444
|
+
| 参数 | 说明 |
|
|
445
|
+
|------|------|
|
|
446
|
+
| `columns` | `(helper) => TableColumnOptions[]`,列定义函数 |
|
|
447
|
+
| `options.index` | 是否显示序号列或自定义序号渲染函数 `(i, record) => VNodeChild` |
|
|
448
|
+
| `options.indexTitle` | 序号列标题,默认 `'#'` |
|
|
449
|
+
| `options.selectable` | 是否可选择或自定义可选择判断函数 `(record) => boolean` |
|
|
450
|
+
| `options.selectType` | `'multiple'` / `'single'`,选择类型 |
|
|
451
|
+
| `options.actions` | 操作按钮列表,内置预设 `{ preset: 'edit' \| 'view' \| 'delete' }` |
|
|
452
|
+
| `options.actionTitle` | 操作列标题,默认 `'操作'` |
|
|
453
|
+
| `options.actionWidth` | 操作列宽度,字符串或根据文案计算宽度函数 |
|
|
454
|
+
| `options.actionHidden` | 是否隐藏操作列 |
|
|
455
|
+
| `options.customizable` | 是否允许自定义列显隐/固定/宽度/排序 |
|
|
456
|
+
| `options.expandable` | 是否可展开行或自定义判断函数 `(record) => boolean` |
|
|
457
|
+
| `options.renderExpand` | `(record, i) => VNodeChild`,展开行渲染函数 |
|
|
458
|
+
|
|
459
|
+
| 属性/方法 | 说明 |
|
|
460
|
+
|-----------|------|
|
|
461
|
+
| `columns` | 响应式列定义 |
|
|
462
|
+
| `custom(modify)` | 自定义列显隐/固定/宽度/排序;传 `true` 重置为默认 |
|
|
463
|
+
| `dataMode` | 数据模式(`all` / `selection`) |
|
|
464
|
+
| `reinit()` | 重新初始化列定义 |
|
|
465
|
+
|
|
466
|
+
### `useDescriptionsHelper(items)`
|
|
467
|
+
|
|
468
|
+
| 参数 | 说明 |
|
|
469
|
+
|------|------|
|
|
470
|
+
| `items` | `(helper) => DescriptionItem[]`,描述项定义函数 |
|
|
471
|
+
|
|
472
|
+
| 属性/方法 | 说明 |
|
|
473
|
+
|-----------|------|
|
|
474
|
+
| `items` | 响应式描述项列表 |
|
|
475
|
+
| `model` | 响应式数据 |
|
|
476
|
+
| `reset(model?, reinit?)` | 重置数据(`reinit=true` 同时重建描述项) |
|
|
477
|
+
| `reinit()` | 重新初始化描述项 |
|
|
478
|
+
|
|
479
|
+
### `useModal(options)`
|
|
480
|
+
|
|
481
|
+
| 参数 | 说明 |
|
|
482
|
+
|------|------|
|
|
483
|
+
| `options.type` | `'dialog'` / `'drawer'`,类型 |
|
|
484
|
+
| `options.title` | 标题 |
|
|
485
|
+
| `options.content` | 内容 |
|
|
486
|
+
| `options.width` | 宽度 |
|
|
487
|
+
| `options.height` | 高度 |
|
|
488
|
+
| `options.confirmText` | 确认按钮文案 |
|
|
489
|
+
| `options.cancelText` | 取消按钮文案 |
|
|
490
|
+
| `options.confirmLoading` | 确认按钮加载状态 |
|
|
491
|
+
| `options.cancelLoading` | 取消按钮加载状态 |
|
|
492
|
+
| `options.onConfirm` | `() => Promise<boolean \| void>`,确认回调,返回 `false` 阻止关闭 |
|
|
493
|
+
| `options.onCancel` | `() => Promise<boolean \| void>`,取消回调 |
|
|
494
|
+
| `options.onClose` | `() => Promise<boolean \| void>`,关闭回调 |
|
|
495
|
+
| `options.closable` | 是否显示关闭按钮,默认 `true` |
|
|
496
|
+
| `options.maskClosable` | 点击遮罩是否关闭,默认 `false` |
|
|
497
|
+
| `options.footer` | 自定义底部内容,`null` 隐藏底部 |
|
|
498
|
+
|
|
499
|
+
| 方法 | 说明 |
|
|
500
|
+
|------|------|
|
|
501
|
+
| `open(title?)` | 打开模态框 |
|
|
502
|
+
| `close()` | 关闭模态框 |
|
|
503
|
+
|
|
504
|
+
### `useModalRef()`
|
|
505
|
+
|
|
506
|
+
| 属性/方法 | 说明 |
|
|
507
|
+
|-----------|------|
|
|
508
|
+
| `inModal` | 是否在模态框上下文内 |
|
|
509
|
+
| `visible` | 模态框可见状态 |
|
|
510
|
+
| `close()` | 关闭模态框 |
|
|
511
|
+
| `setTitle(title)` | 设置模态框标题 |
|
|
512
|
+
|
|
513
|
+
### `useDataPagination(data, options?)`
|
|
514
|
+
|
|
515
|
+
| 参数 | 说明 |
|
|
516
|
+
|------|------|
|
|
517
|
+
| `data` | `MaybeRef<T[]>`,原始数据列表 |
|
|
518
|
+
| `options.pageSize` | 每页条数,默认取插件 `defaultPageSize` |
|
|
519
|
+
| `options.currentPage` | 初始页码,默认 `1` |
|
|
520
|
+
| `options.updateOnChange` | 数据变化时是否重置到第一页,默认 `true` |
|
|
521
|
+
|
|
522
|
+
| 属性/方法 | 说明 |
|
|
523
|
+
|-----------|------|
|
|
524
|
+
| `data` | 当前页数据 |
|
|
525
|
+
| `pagination` | 分页状态(`pageSize`, `currentPage`) |
|
|
526
|
+
| `paginate(params)` | 切换分页 |
|
|
527
|
+
|
|
528
|
+
### 校验规则(`@ithinkdt/page/rules`)
|
|
529
|
+
|
|
530
|
+
| 方法 | 说明 |
|
|
531
|
+
|------|------|
|
|
532
|
+
| `required(message, options?)` | 必填校验,`options.required` 控制是否必填,`options.trigger` 触发时机 |
|
|
533
|
+
| `min(min, message, options?)` | 最小值/最小长度,`min` 为最小阈值 |
|
|
534
|
+
| `max(max, message, options?)` | 最大值/最大长度,`max` 为最大阈值 |
|
|
535
|
+
| `minmax(min, max, message, options?)` | 同时校验最小值/最大长度与最大值/最大长度 |
|
|
536
|
+
| `email(message, options?)` | 邮箱格式 |
|
|
537
|
+
| `phone(message, options?)` | 手机号格式(`1` 开头 11 位数字) |
|
|
538
|
+
| `url(message, options?)` | URL 格式 |
|
|
539
|
+
| `idNo(message, options?)` | 身份证格式 |
|
|
540
|
+
| `plateNo(message, options?)` | 车牌号格式 |
|
|
541
|
+
| `chinese(message, options?)` | 纯中文 |
|
|
542
|
+
| `noChinese(message, options?)` | 不含中文 |
|
|
543
|
+
| `pattern(pattern, message, options?)` | 自定义正则,`pattern` 为 `RegExp` 或正则字符串 |
|
|
544
|
+
| `isRequiredRule(rule)` | 判断是否为 `required` 规则 |
|
|
545
|
+
|
|
546
|
+
> `message` 参数为 `(value, params) => string`,`options.trigger` 默认 `'blur'`(`required` 默认 `['input', 'blur', 'change']`)。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ithinkdt/page",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.19",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "iThinkDT Page",
|
|
@@ -39,19 +39,19 @@
|
|
|
39
39
|
},
|
|
40
40
|
"sideEffects": false,
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@vueuse/core": "^14.
|
|
43
|
-
"nanoid": "^5.1.
|
|
44
|
-
"@ithinkdt/common": "^4.0.
|
|
42
|
+
"@vueuse/core": "^14.3.0",
|
|
43
|
+
"nanoid": "^5.1.11",
|
|
44
|
+
"@ithinkdt/common": "^4.0.8"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"vue": ">=3.5",
|
|
48
48
|
"vue-router": ">=4.5"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"typescript": "~6.0.
|
|
52
|
-
"vite": "^8.0.
|
|
53
|
-
"vue": "^3.5.
|
|
54
|
-
"vue-router": "^5.0.
|
|
51
|
+
"typescript": "~6.0.3",
|
|
52
|
+
"vite": "^8.0.10",
|
|
53
|
+
"vue": "^3.5.34",
|
|
54
|
+
"vue-router": "^5.0.6"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"release": "pnpm publish --no-git-checks"
|
package/src/form.d.ts
CHANGED
|
@@ -124,7 +124,7 @@ export interface FormItemHelper<Model extends {}> extends FromValidation<Model>
|
|
|
124
124
|
): FormItemOptions<Partial<Model>>
|
|
125
125
|
group(
|
|
126
126
|
this: void,
|
|
127
|
-
|
|
127
|
+
visibility: MaybeRef<boolean>,
|
|
128
128
|
items: (FormItemOptions<Partial<Model>> | Falsely)[]
|
|
129
129
|
): FormItemOptions<Partial<Model>>[]
|
|
130
130
|
}
|
|
@@ -162,7 +162,25 @@ export declare function useFormHelper<Model extends {}>(
|
|
|
162
162
|
options?: FormHelperOptions<Model>,
|
|
163
163
|
): FormHelper<Model>
|
|
164
164
|
|
|
165
|
+
export interface FilterHelperOptions<Model extends {}> extends FormHelperOptions<Model> {
|
|
166
|
+
/**
|
|
167
|
+
* 自定义
|
|
168
|
+
*/
|
|
169
|
+
customizable?: boolean | string | undefined
|
|
170
|
+
/**
|
|
171
|
+
* 缓存表单
|
|
172
|
+
*/
|
|
173
|
+
cached?: boolean | string | undefined
|
|
174
|
+
/**
|
|
175
|
+
* 缓存版本,默认 1
|
|
176
|
+
*/
|
|
177
|
+
cacheVersion?: number | undefined
|
|
178
|
+
}
|
|
179
|
+
|
|
165
180
|
export interface FilterHelper<Model extends {}> extends FormHelper<Model> {
|
|
181
|
+
/**
|
|
182
|
+
* 自定义表单项
|
|
183
|
+
*/
|
|
166
184
|
custom(this: void, modify: {
|
|
167
185
|
key: string
|
|
168
186
|
hidden?: boolean | undefined
|
|
@@ -173,20 +191,7 @@ export interface FilterHelper<Model extends {}> extends FormHelper<Model> {
|
|
|
173
191
|
|
|
174
192
|
export declare function useFilterHelper<Model extends {}>(
|
|
175
193
|
items: ((helper: FormItemHelper<Model>) => (FormItemOptions<Partial<Model>> | Falsely)[]),
|
|
176
|
-
options?:
|
|
177
|
-
/**
|
|
178
|
-
* 缓存表单
|
|
179
|
-
*/
|
|
180
|
-
cached?: boolean | string | undefined
|
|
181
|
-
/**
|
|
182
|
-
* 缓存版本,默认 1
|
|
183
|
-
*/
|
|
184
|
-
cacheVersion?: number
|
|
185
|
-
/**
|
|
186
|
-
* 自定义
|
|
187
|
-
*/
|
|
188
|
-
customizable?: boolean | string | undefined
|
|
189
|
-
},
|
|
194
|
+
options?: FilterHelperOptions<Model>,
|
|
190
195
|
): FilterHelper<Model>
|
|
191
196
|
|
|
192
197
|
export interface FormRenderExtraOptions {
|
package/src/form.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toReactive,
|
|
1
|
+
import { StorageSerializers, toReactive, useStorage, useStorageAsync } from '@vueuse/core'
|
|
2
2
|
import { nanoid } from 'nanoid'
|
|
3
3
|
import { computed, h, hasInjectionContext, inject, reactive, readonly, ref, shallowReactive, shallowRef, toRaw, unref } from 'vue'
|
|
4
4
|
import { useRoute } from 'vue-router'
|
|
@@ -93,11 +93,11 @@ export function useFormHelper(items, { initial: initial0, rules, onChange, inFil
|
|
|
93
93
|
return { ...options, name, render: render0, label, __key: nanoid(), beforeSubmit }
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
const group = (
|
|
96
|
+
const group = (visibility, items) => {
|
|
97
97
|
return items.map((item) => {
|
|
98
98
|
return {
|
|
99
99
|
...item,
|
|
100
|
-
hidden: computed(() => unref(
|
|
100
|
+
hidden: computed(() => unref(visibility) == false || unref(item.hidden)),
|
|
101
101
|
}
|
|
102
102
|
})
|
|
103
103
|
}
|
|
@@ -320,7 +320,7 @@ export function useFormHelper(items, { initial: initial0, rules, onChange, inFil
|
|
|
320
320
|
}
|
|
321
321
|
|
|
322
322
|
export function useFilterHelper(items, { customizable = false, cached, cacheVersion = 1, ...options } = {}) {
|
|
323
|
-
const { defaultFilterCached, customizationStorage = localStorage } = (hasInjectionContext() ? inject(PAGE_INJECTION, pageInjection) : pageInjection) ?? {}
|
|
323
|
+
const { defaultFilterCached, customizationStorage = localStorage, cacheStorage = sessionStorage } = (hasInjectionContext() ? inject(PAGE_INJECTION, pageInjection) : pageInjection) ?? {}
|
|
324
324
|
let cacheFn
|
|
325
325
|
const returns = useFormHelper(items, {
|
|
326
326
|
...options,
|
|
@@ -367,7 +367,10 @@ export function useFilterHelper(items, { customizable = false, cached, cacheVers
|
|
|
367
367
|
customizable = 'filter-form-customization#' + useRoute().name
|
|
368
368
|
}
|
|
369
369
|
const customs = customizable
|
|
370
|
-
? useStorageAsync(customizable, getDefaultCustom, customizationStorage, {
|
|
370
|
+
? useStorageAsync(customizable, getDefaultCustom, customizationStorage, {
|
|
371
|
+
onReady: reinit,
|
|
372
|
+
serializer: StorageSerializers.object,
|
|
373
|
+
})
|
|
371
374
|
: ref(getDefaultCustom())
|
|
372
375
|
|
|
373
376
|
if (!customizable) {
|
|
@@ -382,10 +385,13 @@ export function useFilterHelper(items, { customizable = false, cached, cacheVers
|
|
|
382
385
|
if (cached) {
|
|
383
386
|
if (cacheVersion > 1) {
|
|
384
387
|
for (let i = 1; i < cacheVersion; i++) {
|
|
385
|
-
|
|
388
|
+
cacheStorage.removeItem(cached + '-v' + i)
|
|
386
389
|
}
|
|
387
390
|
}
|
|
388
|
-
const cachedModel =
|
|
391
|
+
const cachedModel = useStorage(cached + '-v' + cacheVersion, { ...returns.model }, cacheStorage, {
|
|
392
|
+
mergeDefaults: true,
|
|
393
|
+
serializer: StorageSerializers.object,
|
|
394
|
+
})
|
|
389
395
|
cachedModel.value && returns.reset(cachedModel.value)
|
|
390
396
|
|
|
391
397
|
cacheFn = (model) => {
|
package/src/plugin.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { StorageLikeAsync } from '@vueuse/core'
|
|
1
|
+
import { StorageLike, StorageLikeAsync } from '@vueuse/core'
|
|
2
2
|
import { DefineComponent, InjectionKey, VNodeChild } from 'vue'
|
|
3
3
|
|
|
4
4
|
import { I18nComposable } from '@ithinkdt/common/i18n'
|
|
@@ -56,6 +56,11 @@ export interface PageOptions extends PresetDataSourceOptions {
|
|
|
56
56
|
* 自定义数据存储实现,默认使用 localStorage
|
|
57
57
|
*/
|
|
58
58
|
customizationStorage?: StorageLikeAsync
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 自定义缓存实现,默认使用 sessionStorage
|
|
62
|
+
*/
|
|
63
|
+
cacheStorage?: StorageLike
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
/**
|
package/src/table.d.ts
CHANGED
|
@@ -118,7 +118,7 @@ export interface TableColumnHelper<Model extends {}> {
|
|
|
118
118
|
): TableColumnOptions<Model>
|
|
119
119
|
group(
|
|
120
120
|
this: void,
|
|
121
|
-
|
|
121
|
+
visibility: MaybeRef<boolean>,
|
|
122
122
|
columns: (TableColumnOptions<Model> | Falsely)[]
|
|
123
123
|
): TableColumnOptions<Model>[]
|
|
124
124
|
}
|
package/src/table.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useStorageAsync } from '@vueuse/core'
|
|
1
|
+
import { StorageSerializers, useStorageAsync } from '@vueuse/core'
|
|
2
2
|
import { nanoid } from 'nanoid'
|
|
3
3
|
import { computed, hasInjectionContext, inject, reactive, ref, shallowReactive, shallowRef, toValue, unref } from 'vue'
|
|
4
4
|
import { useRoute } from 'vue-router'
|
|
@@ -112,11 +112,11 @@ export function useTableHelper(columns, { customizable, actions, actionWidth, ac
|
|
|
112
112
|
...options,
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
-
const group = (
|
|
115
|
+
const group = (visibility, cols) => {
|
|
116
116
|
return cols.map((col) => {
|
|
117
117
|
return {
|
|
118
118
|
...col,
|
|
119
|
-
hidden: computed(() => unref(
|
|
119
|
+
hidden: computed(() => unref(visibility) === false || unref(col.hidden)),
|
|
120
120
|
}
|
|
121
121
|
})
|
|
122
122
|
}
|
|
@@ -278,7 +278,10 @@ export function useTableHelper(columns, { customizable, actions, actionWidth, ac
|
|
|
278
278
|
customizable = 'table-column-customization#' + useRoute().name
|
|
279
279
|
}
|
|
280
280
|
const customs = customizable
|
|
281
|
-
? useStorageAsync(customizable, getDefaultCustom, customizationStorage, {
|
|
281
|
+
? useStorageAsync(customizable, getDefaultCustom, customizationStorage, {
|
|
282
|
+
onReady: reinit,
|
|
283
|
+
serializer: StorageSerializers.object,
|
|
284
|
+
})
|
|
282
285
|
: ref(getDefaultCustom())
|
|
283
286
|
|
|
284
287
|
if (!customizable) {
|