@ithinkdt/page 4.0.19 → 4.0.20
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/auto-imports.js +5 -1
- package/package.json +4 -4
- package/src/crud.js +2 -2
- package/src/description.js +14 -4
- package/src/form.d.ts +12 -1
- package/src/form.js +82 -12
- package/src/index.js +1 -0
- package/src/list.d.ts +109 -1
- package/src/list.js +249 -2
- package/src/modal.js +2 -2
- package/src/plugin.d.ts +14 -5
- package/src/table.d.ts +13 -2
- package/src/table.js +196 -118
package/auto-imports.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export const Page = [
|
|
2
2
|
{
|
|
3
3
|
from: '@ithinkdt/page',
|
|
4
|
-
imports: [
|
|
4
|
+
imports: [
|
|
5
|
+
'useDs', 'useDataPagination', 'useFilterHelper', 'useFormHelper', 'useFormModal', 'useDeleteHelper',
|
|
6
|
+
'useSimpleCrud', 'useModal', 'useTableHelper', 'calcActionWidth', 'useDescriptionsHelper',
|
|
7
|
+
'useListPageCustomization',
|
|
8
|
+
],
|
|
5
9
|
},
|
|
6
10
|
]
|
|
7
11
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ithinkdt/page",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "iThinkDT Page",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@vueuse/core": "^14.3.0",
|
|
43
43
|
"nanoid": "^5.1.11",
|
|
44
|
-
"@ithinkdt/common": "^4.0.
|
|
44
|
+
"@ithinkdt/common": "^4.0.9"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"vue": ">=3.5",
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"typescript": "~6.0.3",
|
|
52
|
-
"vite": "^8.0.
|
|
52
|
+
"vite": "^8.0.14",
|
|
53
53
|
"vue": "^3.5.34",
|
|
54
|
-
"vue-router": "^5.0.
|
|
54
|
+
"vue-router": "^5.0.7"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"release": "pnpm publish --no-git-checks"
|
package/src/crud.js
CHANGED
|
@@ -4,7 +4,7 @@ import { useFormModal } from './form.js'
|
|
|
4
4
|
import { IgnoreRejectionError, PAGE_INJECTION, pageInjection } from './plugin.js'
|
|
5
5
|
|
|
6
6
|
export function useDeleteHelper(options) {
|
|
7
|
-
const { i18n: useI18n, keyField, getConfirmRenderer } =
|
|
7
|
+
const { i18n: useI18n, keyField, getConfirmRenderer } = hasInjectionContext() ? inject(PAGE_INJECTION, pageInjection) : pageInjection
|
|
8
8
|
const { t } = useI18n()
|
|
9
9
|
|
|
10
10
|
let onDel
|
|
@@ -136,7 +136,7 @@ function _useSimpleCrudModal(crudType, getItems, request, options) {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
export function useSimpleCrud(options) {
|
|
139
|
-
const { i18n: useI18n } =
|
|
139
|
+
const { i18n: useI18n } = hasInjectionContext() ? inject(PAGE_INJECTION, pageInjection) : pageInjection
|
|
140
140
|
const { t } = useI18n()
|
|
141
141
|
|
|
142
142
|
const createModal = _useSimpleCrudModal('create', options.createItems ?? options.formItems ?? options.items, options.post ?? options.save, options)
|
package/src/description.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { toReactive } from '@vueuse/core'
|
|
2
|
-
import { computed, hasInjectionContext, inject, reactive, ref, shallowReactive, unref } from 'vue'
|
|
1
|
+
import { toReactive, tryOnScopeDispose } from '@vueuse/core'
|
|
2
|
+
import { computed, effectScope, hasInjectionContext, inject, reactive, ref, shallowReactive, unref } from 'vue'
|
|
3
3
|
|
|
4
4
|
import { isNone } from '@ithinkdt/common/object'
|
|
5
5
|
import { uncapitalize } from '@ithinkdt/common/string'
|
|
@@ -103,10 +103,20 @@ export function useDescriptionsHelper(
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
const items0 = shallowReactive([])
|
|
106
|
+
|
|
107
|
+
let scope
|
|
108
|
+
tryOnScopeDispose(() => {
|
|
109
|
+
scope?.stop()
|
|
110
|
+
})
|
|
111
|
+
|
|
106
112
|
function reinit() {
|
|
113
|
+
scope?.stop()
|
|
114
|
+
scope = effectScope()
|
|
107
115
|
items0.length = 0
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
scope.run(() => {
|
|
117
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
118
|
+
items0.push(...items({ it, group, model }).filter(Boolean).map(reactive))
|
|
119
|
+
})
|
|
110
120
|
}
|
|
111
121
|
reinit()
|
|
112
122
|
|
package/src/form.d.ts
CHANGED
|
@@ -166,7 +166,18 @@ export interface FilterHelperOptions<Model extends {}> extends FormHelperOptions
|
|
|
166
166
|
/**
|
|
167
167
|
* 自定义
|
|
168
168
|
*/
|
|
169
|
-
customizable?: boolean | string | undefined
|
|
169
|
+
customizable?: boolean | string | undefined | {
|
|
170
|
+
get: () => Awaitable<string | null>
|
|
171
|
+
set: (value: string) => Awaitable<void>
|
|
172
|
+
remove: () => Awaitable<void>
|
|
173
|
+
/**
|
|
174
|
+
* 事件总线,用于监听配置变化事件,若存在则不会监听 `storage` 事件
|
|
175
|
+
*/
|
|
176
|
+
$change?: {
|
|
177
|
+
on: (callback: (payload: { newValue: unknown }) => void) => void
|
|
178
|
+
off?: (callback: (payload: { newValue: unknown }) => void) => void
|
|
179
|
+
}
|
|
180
|
+
}
|
|
170
181
|
/**
|
|
171
182
|
* 缓存表单
|
|
172
183
|
*/
|
package/src/form.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { StorageSerializers, toReactive,
|
|
1
|
+
import { StorageSerializers, toReactive, tryOnScopeDispose, useEventListener, useStorage } from '@vueuse/core'
|
|
2
2
|
import { nanoid } from 'nanoid'
|
|
3
|
-
import { computed, h, hasInjectionContext, inject, reactive, readonly, ref, shallowReactive, shallowRef, toRaw, unref } from 'vue'
|
|
3
|
+
import { computed, effectScope, h, hasInjectionContext, inject, reactive, readonly, ref, shallowReactive, shallowRef, toRaw, unref, watch } from 'vue'
|
|
4
4
|
import { useRoute } from 'vue-router'
|
|
5
5
|
|
|
6
6
|
import { copy, isNone } from '@ithinkdt/common/object'
|
|
@@ -222,8 +222,17 @@ export function useFormHelper(items, { initial: initial0, rules, onChange, inFil
|
|
|
222
222
|
|
|
223
223
|
const items1 = shallowReactive([])
|
|
224
224
|
|
|
225
|
+
let scope
|
|
226
|
+
tryOnScopeDispose(() => {
|
|
227
|
+
scope?.stop()
|
|
228
|
+
})
|
|
229
|
+
|
|
225
230
|
function reinit() {
|
|
226
|
-
|
|
231
|
+
scope?.stop()
|
|
232
|
+
scope = effectScope()
|
|
233
|
+
scope.run(() => {
|
|
234
|
+
items0.value = items({ model, reset, invalid, validation, validate, restoreValidation, it, group }).filter(Boolean)
|
|
235
|
+
})
|
|
227
236
|
|
|
228
237
|
items1.length = 0
|
|
229
238
|
for (const item of items0.value) {
|
|
@@ -338,11 +347,21 @@ export function useFilterHelper(items, { customizable = false, cached, cacheVers
|
|
|
338
347
|
|
|
339
348
|
const custom = (params) => {
|
|
340
349
|
if (typeof params === 'boolean') {
|
|
341
|
-
if (params)
|
|
350
|
+
if (params) setCustoms(getDefaultCustom())
|
|
342
351
|
} else if (Array.isArray(params)) {
|
|
343
|
-
customs.value.sort = params
|
|
352
|
+
customs.value.sort = JSON.stringify(params) === JSON.stringify(returns.items.map(col => col.name))
|
|
353
|
+
? []
|
|
354
|
+
: params
|
|
355
|
+
setCustoms()
|
|
344
356
|
} else {
|
|
345
357
|
customs.value.hidden[params.key] = 'hidden' in params ? params.hidden : customs.value.hidden[params.key]
|
|
358
|
+
if (!customs.value.hidden[params.key]) {
|
|
359
|
+
delete customs.value.hidden[params.key]
|
|
360
|
+
}
|
|
361
|
+
if (params.hidden) {
|
|
362
|
+
returns.model[params.key] = undefined
|
|
363
|
+
}
|
|
364
|
+
setCustoms()
|
|
346
365
|
}
|
|
347
366
|
const _items = returns.items
|
|
348
367
|
.map((item, i, arr) => {
|
|
@@ -364,14 +383,65 @@ export function useFilterHelper(items, { customizable = false, cached, cacheVers
|
|
|
364
383
|
return ret
|
|
365
384
|
}
|
|
366
385
|
if (customizable === true) {
|
|
367
|
-
customizable =
|
|
386
|
+
customizable = `customization#${useRoute().name}#filter-form`
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const customs = ref(getDefaultCustom())
|
|
390
|
+
let setCustoms = (value = customs.value) => {
|
|
391
|
+
customs.value = value
|
|
392
|
+
}
|
|
393
|
+
if (customizable) {
|
|
394
|
+
let key, storage
|
|
395
|
+
if (typeof customizable === 'object') {
|
|
396
|
+
key = `customization#${useRoute().name}#filter-form`
|
|
397
|
+
storage = {
|
|
398
|
+
get $change() { return customizable.$change },
|
|
399
|
+
getItem: () => customizable.get(),
|
|
400
|
+
setItem: (key, value) => customizable.set(value),
|
|
401
|
+
removeItem: () => customizable.remove(),
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
key = customizable
|
|
405
|
+
storage = customizationStorage
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const read = async (raw) => {
|
|
409
|
+
raw ??= await storage.getItem(key)
|
|
410
|
+
if (raw === null) {
|
|
411
|
+
customs.value = getDefaultCustom()
|
|
412
|
+
return
|
|
413
|
+
}
|
|
414
|
+
const [sort, hidden] = StorageSerializers.object.read(raw)
|
|
415
|
+
customs.value = {
|
|
416
|
+
sort,
|
|
417
|
+
hidden: Object.fromEntries(hidden.map(k => [k, true])),
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
read().then(reinit)
|
|
421
|
+
if (storage.$change) {
|
|
422
|
+
const cb = (payload) => {
|
|
423
|
+
read(payload.newValue).then(reinit)
|
|
424
|
+
}
|
|
425
|
+
storage.$change.on(cb)
|
|
426
|
+
storage.$change.off && tryOnScopeDispose(() => storage.$change.off(cb))
|
|
427
|
+
} else {
|
|
428
|
+
useEventListener(globalThis, 'storage', (event) => {
|
|
429
|
+
if (event.key !== key) return
|
|
430
|
+
Promise.resolve().then(() => read(event.newValue)).then(reinit)
|
|
431
|
+
}, { passive: true })
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
setCustoms = async (value = customs.value) => {
|
|
435
|
+
customs.value = value
|
|
436
|
+
if (value === null) return storage.removeItem(key)
|
|
437
|
+
const sort = value.sort ?? []
|
|
438
|
+
const hidden = Object.keys(value.hidden ?? {}).filter(k => value.hidden[k])
|
|
439
|
+
|
|
440
|
+
if (sort.length === 0 && hidden.length === 0) return storage.removeItem(key)
|
|
441
|
+
const raw = StorageSerializers.object.write([sort, hidden])
|
|
442
|
+
return storage.setItem(key, raw)
|
|
443
|
+
}
|
|
368
444
|
}
|
|
369
|
-
const customs = customizable
|
|
370
|
-
? useStorageAsync(customizable, getDefaultCustom, customizationStorage, {
|
|
371
|
-
onReady: reinit,
|
|
372
|
-
serializer: StorageSerializers.object,
|
|
373
|
-
})
|
|
374
|
-
: ref(getDefaultCustom())
|
|
375
445
|
|
|
376
446
|
if (!customizable) {
|
|
377
447
|
reinit()
|
package/src/index.js
CHANGED
package/src/list.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EventHook } from '@vueuse/core'
|
|
2
|
+
import { Ref } from 'vue'
|
|
3
|
+
|
|
4
|
+
import { Awaitable, Falsely } from '@ithinkdt/common/typed'
|
|
2
5
|
|
|
3
6
|
import { FormItemHelper, FormItemOptions } from './form.js'
|
|
4
7
|
import { TableColumnHelper, TableColumnOptions } from './table.js'
|
|
@@ -8,3 +11,108 @@ export interface ListPageConfig<Model extends {}> {
|
|
|
8
11
|
crud?: (FormItemOptions<Partial<Model>> | Falsely)[] | ((helper: FormItemHelper<Model> & { type: 'create' | 'edit' | 'view' }) => (FormItemOptions<Partial<Model>> | Falsely)[])
|
|
9
12
|
table?: (TableColumnOptions<Model> | Falsely)[] | ((helper: TableColumnHelper<Model>) => (TableColumnOptions<Model> | Falsely)[])
|
|
10
13
|
}
|
|
14
|
+
|
|
15
|
+
export interface CustomAsync {
|
|
16
|
+
get: () => Awaitable<string | null>
|
|
17
|
+
set: (value: string) => Awaitable<void>
|
|
18
|
+
remove: () => Awaitable<void>
|
|
19
|
+
$change: EventHook<{ newValue: unknown }>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface CustomProfile {
|
|
23
|
+
key: string
|
|
24
|
+
name: string | undefined
|
|
25
|
+
locked?: boolean
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface Customizer {
|
|
29
|
+
profiles: Readonly<CustomProfile[]>
|
|
30
|
+
get profile(): string
|
|
31
|
+
set profile(value: string | null | undefined)
|
|
32
|
+
get preference(): string | undefined
|
|
33
|
+
set preference(value: string | null | undefined)
|
|
34
|
+
|
|
35
|
+
get changing(): boolean
|
|
36
|
+
|
|
37
|
+
tableColumn: CustomAsync
|
|
38
|
+
filterForm: CustomAsync
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 复制配置
|
|
42
|
+
*
|
|
43
|
+
* @param key - 配置键
|
|
44
|
+
* @param name - 新的配置名
|
|
45
|
+
* @returns 新的配置键
|
|
46
|
+
*/
|
|
47
|
+
copy(this: void, key: string, name?: string): Promise<string>
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 保存配置
|
|
51
|
+
*
|
|
52
|
+
* @param name - 新的配置名
|
|
53
|
+
* @param key - 配置键,无则更新当前配置
|
|
54
|
+
*/
|
|
55
|
+
save(this: void, name: string, key?: string): void
|
|
56
|
+
/**
|
|
57
|
+
* 保存配置
|
|
58
|
+
*/
|
|
59
|
+
save(this: void, params: {
|
|
60
|
+
/**
|
|
61
|
+
* 新的配置名
|
|
62
|
+
*/
|
|
63
|
+
name: string
|
|
64
|
+
/**
|
|
65
|
+
* 配置键,无则更新当前配置
|
|
66
|
+
*/
|
|
67
|
+
key?: string
|
|
68
|
+
}): void
|
|
69
|
+
/**
|
|
70
|
+
* 移除配置
|
|
71
|
+
*
|
|
72
|
+
* @param key - 配置键
|
|
73
|
+
*/
|
|
74
|
+
remove(this: void, key: string): void
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 锁定配置
|
|
78
|
+
* @param key - 配置键
|
|
79
|
+
* @param locked - 是否锁定
|
|
80
|
+
*/
|
|
81
|
+
lock(this: void, key: string, locked?: boolean): void
|
|
82
|
+
/**
|
|
83
|
+
* 锁定配置
|
|
84
|
+
*/
|
|
85
|
+
lock(this: void, params: {
|
|
86
|
+
/**
|
|
87
|
+
* 配置键
|
|
88
|
+
*/
|
|
89
|
+
key: string
|
|
90
|
+
/**
|
|
91
|
+
* 是否锁定
|
|
92
|
+
*/
|
|
93
|
+
locked?: boolean
|
|
94
|
+
}): void
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export declare function useListPageCustomization(
|
|
98
|
+
options?: {
|
|
99
|
+
/**
|
|
100
|
+
* 是否持久化配置
|
|
101
|
+
*/
|
|
102
|
+
persist?: boolean | 'manual'
|
|
103
|
+
/**
|
|
104
|
+
* 配置键,默认取路由 name
|
|
105
|
+
*/
|
|
106
|
+
key?: string
|
|
107
|
+
/**
|
|
108
|
+
* 从路由 params 取当前配置的参数名
|
|
109
|
+
*/
|
|
110
|
+
routeParamName?: string
|
|
111
|
+
},
|
|
112
|
+
): Omit<Customizer, 'profiles' | 'profile' | 'default' | 'changing'> & {
|
|
113
|
+
customizer: Customizer
|
|
114
|
+
profiles: Ref<CustomProfile[]>
|
|
115
|
+
profile: Ref<string, string | null | undefined>
|
|
116
|
+
preference: Ref<string | undefined, string | null | undefined>
|
|
117
|
+
changing: Ref<boolean>
|
|
118
|
+
}
|
package/src/list.js
CHANGED
|
@@ -1,2 +1,249 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { StorageSerializers, createEventHook, tryOnScopeDispose, useStorageAsync } from '@vueuse/core'
|
|
2
|
+
import { nanoid } from 'nanoid'
|
|
3
|
+
import { computed, hasInjectionContext, inject, markRaw, nextTick, reactive, ref } from 'vue'
|
|
4
|
+
import { useRoute } from 'vue-router'
|
|
5
|
+
|
|
6
|
+
import { debounce } from '@ithinkdt/common/fn'
|
|
7
|
+
|
|
8
|
+
import { PAGE_INJECTION, pageInjection } from './plugin.js'
|
|
9
|
+
|
|
10
|
+
class CustomStorage {
|
|
11
|
+
constructor(type, storage, key, profile, { onSet } = {}) {
|
|
12
|
+
this.type = type
|
|
13
|
+
this.storage = storage
|
|
14
|
+
this.key = key
|
|
15
|
+
this.profile = profile
|
|
16
|
+
this.onSet = onSet
|
|
17
|
+
|
|
18
|
+
this.$change = createEventHook()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get storeKey() {
|
|
22
|
+
return `customization#${this.key}~${this.profile}#${this.type}`
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get() {
|
|
26
|
+
return this.storage.getItem(this.storeKey)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async set(value) {
|
|
30
|
+
await this.onSet?.(value, this)
|
|
31
|
+
const oldValue = await this.get()
|
|
32
|
+
if (value === oldValue) return
|
|
33
|
+
await this.storage.setItem(this.storeKey, value)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
remove() {
|
|
37
|
+
return this.storage.removeItem(this.storeKey)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function useListPageCustomization({
|
|
42
|
+
persist = true,
|
|
43
|
+
key,
|
|
44
|
+
routeParamName = 'profile',
|
|
45
|
+
} = {}) {
|
|
46
|
+
const route = useRoute()
|
|
47
|
+
key ??= route.name
|
|
48
|
+
|
|
49
|
+
const { customizationStorage = localStorage, i18n: useI18n } = hasInjectionContext() ? inject(PAGE_INJECTION, pageInjection) : pageInjection
|
|
50
|
+
const { t } = useI18n()
|
|
51
|
+
|
|
52
|
+
let storage
|
|
53
|
+
if (persist) {
|
|
54
|
+
storage = customizationStorage
|
|
55
|
+
} else {
|
|
56
|
+
const store = {}
|
|
57
|
+
storage = {
|
|
58
|
+
getItem: key => store[key] ?? null,
|
|
59
|
+
setItem: (key, value) => { store[key] = value },
|
|
60
|
+
removeItem: (key) => { delete store[key] },
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const { promise: ready, resolve } = Promise.withResolvers()
|
|
65
|
+
|
|
66
|
+
const changing = ref(false)
|
|
67
|
+
|
|
68
|
+
const debounceResetChanged = debounce(() => {
|
|
69
|
+
changing.value = false
|
|
70
|
+
}, 2000)
|
|
71
|
+
|
|
72
|
+
const getDefaultName = (i, namePrefix = t('common.page.custom.profile')) => {
|
|
73
|
+
const name = `${namePrefix}${i}`
|
|
74
|
+
if (config.value.profiles.some(profile => profile.name === name)) return getDefaultName(i + 1, namePrefix)
|
|
75
|
+
return name
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const onSet = async (newValue, storage) => {
|
|
79
|
+
const profile = config.value.profiles.find(profile => profile.key === storage.profile)
|
|
80
|
+
if (profile?.locked) {
|
|
81
|
+
const profileName = getDefaultName(1, profile.key === 'default' ? undefined : profile?.name)
|
|
82
|
+
const profileKey = nanoid()
|
|
83
|
+
const index = config.value.profiles.findIndex(profile => profile.key === storage.profile)
|
|
84
|
+
config.value.profiles.splice(index + 1, 0, { key: profileKey, name: profileName })
|
|
85
|
+
await switchProfile(profileKey, false)
|
|
86
|
+
}
|
|
87
|
+
changing.value = true
|
|
88
|
+
debounceResetChanged()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const filterStorage = new CustomStorage('filter-form', storage, key, 'default', { onSet })
|
|
92
|
+
const tableStorage = new CustomStorage('table-column', storage, key, 'default', { onSet })
|
|
93
|
+
tryOnScopeDispose(() => {
|
|
94
|
+
filterStorage.$event.clear()
|
|
95
|
+
tableStorage.$event.clear()
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
let laskKey = 'default'
|
|
99
|
+
async function switchProfile(key, emitChange) {
|
|
100
|
+
if (!key) {
|
|
101
|
+
await ready
|
|
102
|
+
key = config.value.preference ?? config.value.latest ?? 'default'
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
emitChange ??= key !== laskKey
|
|
106
|
+
laskKey = key
|
|
107
|
+
config.value.latest = key
|
|
108
|
+
filterStorage.profile = key
|
|
109
|
+
tableStorage.profile = key
|
|
110
|
+
|
|
111
|
+
if (!emitChange) return
|
|
112
|
+
const [filterForm, tableColumn] = await Promise.all([
|
|
113
|
+
filterStorage.get(),
|
|
114
|
+
tableStorage.get(),
|
|
115
|
+
])
|
|
116
|
+
filterStorage.$change.trigger({
|
|
117
|
+
newValue: filterForm,
|
|
118
|
+
})
|
|
119
|
+
tableStorage.$change.trigger({
|
|
120
|
+
newValue: tableColumn,
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const config = useStorageAsync(
|
|
125
|
+
`customization#${key}#profile-info`,
|
|
126
|
+
{
|
|
127
|
+
latest: 'default',
|
|
128
|
+
preference: undefined,
|
|
129
|
+
profiles: [
|
|
130
|
+
{ key: 'default', locked: true },
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
storage,
|
|
134
|
+
{
|
|
135
|
+
writeDefaults: false,
|
|
136
|
+
serializer: StorageSerializers.object,
|
|
137
|
+
onReady() {
|
|
138
|
+
resolve()
|
|
139
|
+
nextTick(() => {
|
|
140
|
+
config.value.profiles[0].name = t('common.page.custom.profileDefault')
|
|
141
|
+
const key = route.params[routeParamName]
|
|
142
|
+
switchProfile(key)
|
|
143
|
+
})
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
const profile = computed({
|
|
149
|
+
get: () => config.value.latest ?? 'default',
|
|
150
|
+
set: (key) => {
|
|
151
|
+
if (key !== config.value.latest) switchProfile(key)
|
|
152
|
+
},
|
|
153
|
+
})
|
|
154
|
+
const preference = computed({
|
|
155
|
+
get: () => config.value.preference,
|
|
156
|
+
set: (key) => {
|
|
157
|
+
config.value.preference = key ?? undefined
|
|
158
|
+
},
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
function removeProfile(key) {
|
|
162
|
+
const removeProfile = config.value.profiles.find(profile => profile.key === key)
|
|
163
|
+
|
|
164
|
+
let newProfiles = config.value.profiles
|
|
165
|
+
if (removeProfile) {
|
|
166
|
+
newProfiles = config.value.profiles.filter(profile => profile.key !== key)
|
|
167
|
+
}
|
|
168
|
+
config.value.profiles = newProfiles
|
|
169
|
+
if (preference.value === key) {
|
|
170
|
+
preference.value = undefined
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (profile.value === key) {
|
|
174
|
+
config.value.latest = undefined
|
|
175
|
+
switchProfile()
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
storage.removeItem(
|
|
179
|
+
`customization#${filterStorage.key}~${key}#${filterStorage.type}`,
|
|
180
|
+
)
|
|
181
|
+
storage.removeItem(
|
|
182
|
+
`customization#${tableStorage.key}~${key}#${tableStorage.type}`,
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function saveProfile(name, key) {
|
|
187
|
+
if (typeof name === 'object') {
|
|
188
|
+
name = name.name
|
|
189
|
+
key = name.key
|
|
190
|
+
}
|
|
191
|
+
key ??= config.value.latest
|
|
192
|
+
const profile = config.value.profiles.find(profile => profile.key === key)
|
|
193
|
+
if (!profile) {
|
|
194
|
+
console.debug(`[customizer] profile not found: ${key}`)
|
|
195
|
+
return
|
|
196
|
+
}
|
|
197
|
+
profile.name = name
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function copyProfile(key, name) {
|
|
201
|
+
const index = config.value.profiles.findIndex(profile => profile.key === key)
|
|
202
|
+
if (index === -1) {
|
|
203
|
+
console.debug(`[customizer] profile not found: ${key}`)
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
const newProfile = { key: nanoid(), name: name ?? getDefaultName(1, config.value.profiles[index].name) }
|
|
207
|
+
config.value.profiles.splice(index + 1, 0, newProfile)
|
|
208
|
+
await Promise.all([
|
|
209
|
+
storage.setItem(
|
|
210
|
+
`customization#${filterStorage.key}~${newProfile.key}#${filterStorage.type}`,
|
|
211
|
+
await storage.getItem(`customization#${filterStorage.key}~${key}#${filterStorage.type}`),
|
|
212
|
+
),
|
|
213
|
+
storage.setItem(
|
|
214
|
+
`customization#${tableStorage.key}~${newProfile.key}#${tableStorage.type}`,
|
|
215
|
+
await storage.getItem(`customization#${tableStorage.key}~${key}#${tableStorage.type}`),
|
|
216
|
+
),
|
|
217
|
+
])
|
|
218
|
+
profile.value = newProfile.key
|
|
219
|
+
return newProfile.key
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function lockProfile(key, locked) {
|
|
223
|
+
if (typeof key === 'object') {
|
|
224
|
+
key = key.key
|
|
225
|
+
locked = key.locked
|
|
226
|
+
}
|
|
227
|
+
const profile = config.value.profiles.find(profile => profile.key === key)
|
|
228
|
+
if (!profile) {
|
|
229
|
+
console.debug(`[customizer] profile not found: ${key}`)
|
|
230
|
+
return
|
|
231
|
+
}
|
|
232
|
+
profile.locked = locked
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const returns = {
|
|
236
|
+
profiles: computed(() => config.value.profiles),
|
|
237
|
+
profile,
|
|
238
|
+
preference,
|
|
239
|
+
changing,
|
|
240
|
+
remove: removeProfile,
|
|
241
|
+
save: saveProfile,
|
|
242
|
+
copy: copyProfile,
|
|
243
|
+
lock: lockProfile,
|
|
244
|
+
filterForm: markRaw(filterStorage),
|
|
245
|
+
tableColumn: markRaw(tableStorage),
|
|
246
|
+
}
|
|
247
|
+
returns.customizer = reactive(returns)
|
|
248
|
+
return returns
|
|
249
|
+
}
|
package/src/modal.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tryOnScopeDispose } from '@vueuse/core'
|
|
2
2
|
import { nanoid } from 'nanoid'
|
|
3
3
|
import { computed, defineComponent, h, hasInjectionContext, inject, isVNode, provide, reactive, ref, toValue, unref } from 'vue'
|
|
4
4
|
|
|
@@ -120,7 +120,7 @@ export function useModal({ content, confirmText, confirmLoading, cancelText, can
|
|
|
120
120
|
|
|
121
121
|
const removeModal = addModal(h(Wrapper, { key: nanoid() }))
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
tryOnScopeDispose(removeModal)
|
|
124
124
|
const returns = [open, close]
|
|
125
125
|
returns.open = open
|
|
126
126
|
returns.close = close
|
package/src/plugin.d.ts
CHANGED
|
@@ -31,6 +31,8 @@ export interface PageOptions extends PresetDataSourceOptions {
|
|
|
31
31
|
'common.page.table.presetAction.editTitle': string
|
|
32
32
|
'common.page.table.presetAction.viewTitle': string
|
|
33
33
|
'common.page.table.presetAction.deleteTitle': string
|
|
34
|
+
'common.page.custom.profile': string
|
|
35
|
+
'common.page.custom.profileDefault': string
|
|
34
36
|
}>
|
|
35
37
|
|
|
36
38
|
getConfirmRenderer: () => ((params: CrudConfirmParams) => void)
|
|
@@ -49,14 +51,21 @@ export interface PageOptions extends PresetDataSourceOptions {
|
|
|
49
51
|
index: number,
|
|
50
52
|
) => VNodeChild)
|
|
51
53
|
/**
|
|
52
|
-
*
|
|
54
|
+
* 自定义配置存储实现,默认使用 localStorage
|
|
53
55
|
*/
|
|
54
|
-
|
|
56
|
+
customizationStorage?: StorageLikeAsync & {
|
|
57
|
+
/**
|
|
58
|
+
* 事件总线,用于监听配置变化事件,若存在则不会监听 `storage` 事件
|
|
59
|
+
*/
|
|
60
|
+
$change?: {
|
|
61
|
+
on: (callback: (payload: { newValue: unknown }) => void) => void
|
|
62
|
+
off?: (callback: (payload: { newValue: unknown }) => void) => void
|
|
63
|
+
}
|
|
64
|
+
}
|
|
55
65
|
/**
|
|
56
|
-
*
|
|
66
|
+
* 是否默认缓存 filter 表单数据
|
|
57
67
|
*/
|
|
58
|
-
|
|
59
|
-
|
|
68
|
+
defaultFilterCached?: boolean
|
|
60
69
|
/**
|
|
61
70
|
* 自定义缓存实现,默认使用 sessionStorage
|
|
62
71
|
*/
|
package/src/table.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MaybeRef, MaybeRefOrGetter, Ref, VNodeChild } from 'vue'
|
|
2
2
|
|
|
3
|
-
import { Falsely } from '@ithinkdt/common/typed'
|
|
3
|
+
import { Awaitable, Falsely } from '@ithinkdt/common/typed'
|
|
4
4
|
|
|
5
5
|
import { DescriptionTypePresets } from './description'
|
|
6
6
|
|
|
@@ -161,7 +161,18 @@ export interface TableOptions<Model extends {}> {
|
|
|
161
161
|
actionTitle?: MaybeRefOrGetter<VNodeChild>
|
|
162
162
|
actionWidth?: MaybeRef<number | string | undefined> | ((actionTexts: string[]) => number | string)
|
|
163
163
|
actionHidden?: MaybeRef<boolean | undefined>
|
|
164
|
-
customizable?: boolean | string | undefined
|
|
164
|
+
customizable?: boolean | string | undefined | {
|
|
165
|
+
get: () => Awaitable<string | null>
|
|
166
|
+
set: (value: string) => Awaitable<void>
|
|
167
|
+
remove: () => Awaitable<void>
|
|
168
|
+
/**
|
|
169
|
+
* 事件总线,用于监听配置变化事件,若存在则不会监听 `storage` 事件
|
|
170
|
+
*/
|
|
171
|
+
$change?: {
|
|
172
|
+
on: (callback: (payload: { newValue: unknown }) => void) => void
|
|
173
|
+
off?: (callback: (payload: { newValue: unknown }) => void) => void
|
|
174
|
+
}
|
|
175
|
+
}
|
|
165
176
|
}
|
|
166
177
|
|
|
167
178
|
export interface TableHelper<Model extends {}> {
|
package/src/table.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { StorageSerializers,
|
|
1
|
+
import { StorageSerializers, tryOnScopeDispose, useEventListener } from '@vueuse/core'
|
|
2
2
|
import { nanoid } from 'nanoid'
|
|
3
|
-
import { computed, hasInjectionContext, inject, reactive, ref, shallowReactive, shallowRef, toValue, unref } from 'vue'
|
|
3
|
+
import { computed, effectScope, hasInjectionContext, inject, reactive, ref, shallowReactive, shallowRef, toValue, unref } from 'vue'
|
|
4
4
|
import { useRoute } from 'vue-router'
|
|
5
5
|
|
|
6
6
|
import { isNone } from '@ithinkdt/common/object'
|
|
@@ -126,13 +126,26 @@ export function useTableHelper(columns, { customizable, actions, actionWidth, ac
|
|
|
126
126
|
|
|
127
127
|
const custom = (params) => {
|
|
128
128
|
if (typeof params === 'boolean') {
|
|
129
|
-
if (params)
|
|
129
|
+
if (params) setCustoms(getDefaultCustom())
|
|
130
130
|
} else if (Array.isArray(params)) {
|
|
131
|
-
customs.value.sort = params
|
|
131
|
+
customs.value.sort = JSON.stringify(params) === JSON.stringify(columns0.value.map(col => col.key))
|
|
132
|
+
? []
|
|
133
|
+
: params
|
|
134
|
+
setCustoms()
|
|
132
135
|
} else {
|
|
133
136
|
customs.value.hidden[params.key] = 'hidden' in params ? params.hidden : customs.value.hidden[params.key]
|
|
134
137
|
customs.value.fixed[params.key] = 'fixed' in params ? params.fixed : customs.value.fixed[params.key]
|
|
135
138
|
customs.value.width[params.key] = 'width' in params ? params.width : customs.value.width[params.key]
|
|
139
|
+
if (!customs.value.hidden[params.key]) {
|
|
140
|
+
delete customs.value.hidden[params.key]
|
|
141
|
+
}
|
|
142
|
+
if (!customs.value.fixed[params.key]) {
|
|
143
|
+
delete customs.value.fixed[params.key]
|
|
144
|
+
}
|
|
145
|
+
if (!customs.value.width[params.key]) {
|
|
146
|
+
delete customs.value.width[params.key]
|
|
147
|
+
}
|
|
148
|
+
setCustoms()
|
|
136
149
|
}
|
|
137
150
|
const columns2 = columns0.value.map((col, i, arr) => {
|
|
138
151
|
const index = customs.value.sort.indexOf(col.key)
|
|
@@ -149,140 +162,205 @@ export function useTableHelper(columns, { customizable, actions, actionWidth, ac
|
|
|
149
162
|
columns1.push(...columns2.toSorted((a, b) => a.__order - b.__order))
|
|
150
163
|
}
|
|
151
164
|
|
|
165
|
+
let scope
|
|
166
|
+
tryOnScopeDispose(() => {
|
|
167
|
+
scope?.stop()
|
|
168
|
+
})
|
|
169
|
+
|
|
152
170
|
function reinit() {
|
|
153
|
-
|
|
171
|
+
scope?.stop()
|
|
172
|
+
scope = effectScope()
|
|
173
|
+
scope.run(() => {
|
|
174
|
+
columns0.value = columns({ col, cols, group }).filter(Boolean)
|
|
154
175
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
176
|
+
if (actions) {
|
|
177
|
+
if (Array.isArray(actions)) {
|
|
178
|
+
for (const act of actions) {
|
|
179
|
+
if (!act.preset) continue
|
|
180
|
+
act.title ??= act.preset === 'edit'
|
|
181
|
+
? () => t('common.page.table.presetAction.editTitle')
|
|
182
|
+
: act.preset === 'view'
|
|
183
|
+
? () => t('common.page.table.presetAction.viewTitle')
|
|
184
|
+
: act.preset === 'delete'
|
|
185
|
+
? () => t('common.page.table.presetAction.deleteTitle')
|
|
186
|
+
: ''
|
|
187
|
+
act.text ??= act.preset === 'edit'
|
|
188
|
+
? () => t('common.page.crud.editTitle')
|
|
189
|
+
: act.preset === 'view'
|
|
190
|
+
? () => t('common.page.crud.viewTitle')
|
|
191
|
+
: act.preset === 'delete'
|
|
192
|
+
? () => t('common.page.crud.deleteTitle')
|
|
193
|
+
: ''
|
|
173
194
|
|
|
174
|
-
|
|
195
|
+
act.color ??= act.preset === 'delete' ? 'danger' : 'primary'
|
|
196
|
+
}
|
|
175
197
|
}
|
|
176
|
-
}
|
|
177
198
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
199
|
+
let width
|
|
200
|
+
if (typeof actionWidth === 'function') {
|
|
201
|
+
if (typeof actions === 'function') {
|
|
202
|
+
console.warn(`[table] actions 为函数时,actionWidth 不能为函数!`)
|
|
203
|
+
} else {
|
|
204
|
+
width = computed(() => actionWidth(
|
|
205
|
+
actions.filter(act => unref(act.auth) !== false).map(act => toValue(act.text))),
|
|
206
|
+
)
|
|
207
|
+
}
|
|
182
208
|
} else {
|
|
183
|
-
width =
|
|
184
|
-
actions.filter(act => unref(act.auth) !== false).map(act => toValue(act.text))),
|
|
185
|
-
)
|
|
209
|
+
width = actionWidth ?? 140
|
|
186
210
|
}
|
|
187
|
-
|
|
188
|
-
|
|
211
|
+
|
|
212
|
+
columns0.value.push(
|
|
213
|
+
col(
|
|
214
|
+
'$actions',
|
|
215
|
+
actionTitle ?? (() => t('common.page.table.actionTitle')),
|
|
216
|
+
typeof actions === 'function'
|
|
217
|
+
? (value, record, i) => actions(record, i)
|
|
218
|
+
: (value, record, i) => {
|
|
219
|
+
const action0 = actions.filter((act) => {
|
|
220
|
+
return unref(act.auth) !== false && act.hidden?.(record, i) !== true
|
|
221
|
+
})
|
|
222
|
+
.map(act => ({
|
|
223
|
+
...act,
|
|
224
|
+
text: toValue(act.text),
|
|
225
|
+
title: toValue(act.title),
|
|
226
|
+
disabled: act.disabled?.(record, i),
|
|
227
|
+
color: typeof act.color === 'function' ? act.color(record, i) : act.color,
|
|
228
|
+
onClick: ev => act.onClick?.(record, i, ev),
|
|
229
|
+
}))
|
|
230
|
+
return getTableActionsRenderer()(action0, record, i)
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
fixed: 'right',
|
|
234
|
+
width,
|
|
235
|
+
ellipsis: false,
|
|
236
|
+
hidden: computed(() => unref(actionHidden) ?? (Array.isArray(actions) && actions.length === 0)),
|
|
237
|
+
},
|
|
238
|
+
),
|
|
239
|
+
)
|
|
189
240
|
}
|
|
190
241
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
242
|
+
if (index) {
|
|
243
|
+
columns0.value.unshift(
|
|
244
|
+
col(
|
|
245
|
+
'$index',
|
|
246
|
+
indexTitle ?? (() => t('common.page.table.indexTitle')),
|
|
247
|
+
typeof actions === 'function'
|
|
248
|
+
? (value, record, i) => index(i, record)
|
|
249
|
+
: (value, record, i) => {
|
|
250
|
+
const base = unref(index) === true ? 0 : unref(index)
|
|
251
|
+
return (base + i + 1).toString()
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
hidden: computed(() => unref(index) === false),
|
|
255
|
+
width: 70,
|
|
256
|
+
maxWidth: 100,
|
|
257
|
+
align: 'center',
|
|
258
|
+
fixed: 'left',
|
|
259
|
+
},
|
|
260
|
+
),
|
|
261
|
+
)
|
|
262
|
+
}
|
|
263
|
+
if (expandable) {
|
|
264
|
+
columns0.value.unshift(
|
|
211
265
|
{
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
266
|
+
key: '$expand',
|
|
267
|
+
prop: '$expand',
|
|
268
|
+
type: 'expand',
|
|
269
|
+
expandable: typeof expandable === 'function' ? expandable : undefined,
|
|
270
|
+
renderExpand,
|
|
271
|
+
hidden: computed(() => unref(expandable) === false),
|
|
272
|
+
fixed: 'left',
|
|
273
|
+
visible: false,
|
|
216
274
|
},
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if (index) {
|
|
222
|
-
columns0.value.unshift(
|
|
223
|
-
col(
|
|
224
|
-
'$index',
|
|
225
|
-
indexTitle ?? (() => t('common.page.table.indexTitle')),
|
|
226
|
-
typeof actions === 'function'
|
|
227
|
-
? (value, record, i) => index(i, record)
|
|
228
|
-
: (value, record, i) => {
|
|
229
|
-
const base = unref(index) === true ? 0 : unref(index)
|
|
230
|
-
return (base + i + 1).toString()
|
|
231
|
-
},
|
|
275
|
+
)
|
|
276
|
+
}
|
|
277
|
+
if (selectable) {
|
|
278
|
+
columns0.value.unshift(
|
|
232
279
|
{
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
280
|
+
key: '$selection',
|
|
281
|
+
prop: '$selection',
|
|
282
|
+
type: 'selection',
|
|
283
|
+
selectType,
|
|
284
|
+
selectMenus,
|
|
285
|
+
selectable: typeof selectable === 'function' ? selectable : undefined,
|
|
286
|
+
hidden: computed(() => unref(selectable) === false),
|
|
237
287
|
fixed: 'left',
|
|
288
|
+
width: 50,
|
|
289
|
+
maxWidth: 50,
|
|
290
|
+
visible: false,
|
|
238
291
|
},
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
if (expandable) {
|
|
243
|
-
columns0.value.unshift(
|
|
244
|
-
{
|
|
245
|
-
key: '$expand',
|
|
246
|
-
prop: '$expand',
|
|
247
|
-
type: 'expand',
|
|
248
|
-
expandable: typeof expandable === 'function' ? expandable : undefined,
|
|
249
|
-
renderExpand,
|
|
250
|
-
hidden: computed(() => unref(expandable) === false),
|
|
251
|
-
fixed: 'left',
|
|
252
|
-
visible: false,
|
|
253
|
-
},
|
|
254
|
-
)
|
|
255
|
-
}
|
|
256
|
-
if (selectable) {
|
|
257
|
-
columns0.value.unshift(
|
|
258
|
-
{
|
|
259
|
-
key: '$selection',
|
|
260
|
-
prop: '$selection',
|
|
261
|
-
type: 'selection',
|
|
262
|
-
selectType,
|
|
263
|
-
selectMenus,
|
|
264
|
-
selectable: typeof selectable === 'function' ? selectable : undefined,
|
|
265
|
-
hidden: computed(() => unref(selectable) === false),
|
|
266
|
-
fixed: 'left',
|
|
267
|
-
width: 50,
|
|
268
|
-
maxWidth: 50,
|
|
269
|
-
visible: false,
|
|
270
|
-
},
|
|
271
|
-
)
|
|
272
|
-
}
|
|
292
|
+
)
|
|
293
|
+
}
|
|
294
|
+
})
|
|
273
295
|
|
|
274
296
|
custom(false)
|
|
275
297
|
}
|
|
276
298
|
|
|
277
299
|
if (customizable === true) {
|
|
278
|
-
customizable =
|
|
300
|
+
customizable = `customization#${useRoute().name}#table-column`
|
|
301
|
+
}
|
|
302
|
+
const customs = ref(getDefaultCustom())
|
|
303
|
+
let setCustoms = (value = customs.value) => {
|
|
304
|
+
customs.value = value
|
|
305
|
+
}
|
|
306
|
+
if (customizable) {
|
|
307
|
+
let key, storage
|
|
308
|
+
if (typeof customizable === 'object') {
|
|
309
|
+
key = `customization#${useRoute().name}#table-column`
|
|
310
|
+
storage = {
|
|
311
|
+
get $change() { return customizable.$change },
|
|
312
|
+
getItem: () => customizable.get(),
|
|
313
|
+
setItem: (key, value) => customizable.set(value),
|
|
314
|
+
removeItem: () => customizable.remove(),
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
key = customizable
|
|
318
|
+
storage = customizationStorage
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const read = async (raw) => {
|
|
322
|
+
if (raw === undefined) {
|
|
323
|
+
raw = await storage.getItem(key)
|
|
324
|
+
}
|
|
325
|
+
if (raw === null) {
|
|
326
|
+
customs.value = getDefaultCustom()
|
|
327
|
+
return
|
|
328
|
+
}
|
|
329
|
+
const [sort, hidden, fixed, width] = StorageSerializers.object.read(raw)
|
|
330
|
+
customs.value = {
|
|
331
|
+
sort,
|
|
332
|
+
hidden: Object.fromEntries(hidden.map(k => [k, true])),
|
|
333
|
+
fixed: Object.fromEntries(fixed.map(k => [k, true])),
|
|
334
|
+
width,
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
read().then(reinit)
|
|
338
|
+
if (storage.$change) {
|
|
339
|
+
const cb = (payload) => {
|
|
340
|
+
read(payload.newValue).then(reinit)
|
|
341
|
+
}
|
|
342
|
+
storage.$change.on(cb)
|
|
343
|
+
storage.$change.off && tryOnScopeDispose(() => storage.$change.off(cb))
|
|
344
|
+
} else {
|
|
345
|
+
useEventListener(globalThis, 'storage', (event) => {
|
|
346
|
+
if (event.key !== key) return
|
|
347
|
+
Promise.resolve().then(() => read(event.newValue)).then(reinit)
|
|
348
|
+
}, { passive: true })
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
setCustoms = async (value = customs.value) => {
|
|
352
|
+
customs.value = value
|
|
353
|
+
if (value === null) return storage.removeItem(key)
|
|
354
|
+
const sort = value.sort ?? []
|
|
355
|
+
const hidden = Object.keys(value.hidden ?? {}).filter(k => value.hidden[k])
|
|
356
|
+
const fixed = Object.keys(value.fixed ?? {}).filter(k => value.fixed[k])
|
|
357
|
+
const width = value.width ?? {}
|
|
358
|
+
|
|
359
|
+
if (sort.length === 0 && hidden.length === 0 && fixed.length === 0 && Object.keys(width).length === 0) return storage.removeItem(key)
|
|
360
|
+
const raw = StorageSerializers.object.write([sort, hidden, fixed, width])
|
|
361
|
+
return storage.setItem(key, raw)
|
|
362
|
+
}
|
|
279
363
|
}
|
|
280
|
-
const customs = customizable
|
|
281
|
-
? useStorageAsync(customizable, getDefaultCustom, customizationStorage, {
|
|
282
|
-
onReady: reinit,
|
|
283
|
-
serializer: StorageSerializers.object,
|
|
284
|
-
})
|
|
285
|
-
: ref(getDefaultCustom())
|
|
286
364
|
|
|
287
365
|
if (!customizable) {
|
|
288
366
|
reinit()
|