@mythpe/quasar-ui-qui 0.1.19 → 0.1.21

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.
@@ -0,0 +1,945 @@
1
+ import type { MaybeRefOrGetter } from 'vue'
2
+ import { computed, nextTick, reactive, ref, toRef, toValue, useSlots } from 'vue'
3
+ import type {
4
+ ApiServiceParams,
5
+ FetchRowsArgs,
6
+ MDatatableFilterForm,
7
+ MDatatableMetaServer,
8
+ MDatatableOptions,
9
+ MDatatablePagination,
10
+ MDatatableProps, MDatatableScope,
11
+ MDtExportOptions,
12
+ MDtHeadersParameter,
13
+ MDtItem,
14
+ MDtItemIndex,
15
+ MDtMythApiServicesSchema
16
+ } from '../types'
17
+ import { useI18n } from 'vue-i18n'
18
+ import { useMyth } from './useMyth'
19
+ import { useQuasar } from 'quasar'
20
+ import lodash from 'lodash'
21
+ import { useRoute, useRouter } from 'vue-router'
22
+ import type { AxiosRequestConfig } from 'axios'
23
+ import { useResetForm, useSetFormValues } from 'vee-validate'
24
+
25
+ const initPaginationOptions: MDatatablePagination = {
26
+ sortBy: undefined,
27
+ descending: undefined,
28
+ page: 1,
29
+ rowsPerPage: 50,
30
+ rowsNumber: 0
31
+ }
32
+ export const initMetaServer: MDatatableMetaServer = {
33
+ current_page: null,
34
+ last_page: null,
35
+ total: null
36
+ }
37
+
38
+ export const useDtHelpers = (options: MaybeRefOrGetter<MDatatableProps>) => {
39
+ const slots = useSlots()
40
+ const $q = useQuasar()
41
+ const router = useRouter()
42
+ const route = useRoute()
43
+ const { te } = useI18n({ useScope: 'global' })
44
+ const {
45
+ __,
46
+ props: pluginOptions,
47
+ parseHeaders,
48
+ pascalCase,
49
+ pluralize,
50
+ downloadFromResponse,
51
+ api,
52
+ alertError,
53
+ alertSuccess,
54
+ confirmMessage
55
+ } = useMyth()
56
+ const props = toValue(options)
57
+ const getRows = ref<MDtItem[]>([])
58
+ const defaultItem = computed(() => props.defaultItem)
59
+ const getTableTitle = computed(() => {
60
+ if (props.title) {
61
+ if (te(props.title)) {
62
+ return __(props.title)
63
+ }
64
+ return __('replace.index', { name: __(props.title) })
65
+ }
66
+ return undefined
67
+ })
68
+ const serviceName = computed(() => props.serviceName)
69
+ const exportToBlob = computed(() => {
70
+ if (props.exportUrl === undefined && pluginOptions.value.datatable?.exportUrl === undefined) {
71
+ return !0
72
+ }
73
+ const t = props.exportUrl === undefined ? pluginOptions.value.datatable?.exportUrl : props.exportUrl
74
+ if (t !== undefined) {
75
+ if (t.toString() === 'true' || t.toString() === '') {
76
+ return !1
77
+ }
78
+ if (t.toString() === 'pdf') {
79
+ return 'excel'
80
+ }
81
+ if (t.toString() === 'excel') {
82
+ return 'pdf'
83
+ }
84
+ }
85
+ return !0
86
+ })
87
+
88
+ const filterDialogModel = ref(!1)
89
+ const showDialogModel = ref(!1)
90
+ const formDialogModel = ref(!1)
91
+ const isUpdateDialog = ref(!1)
92
+ const dialogItem = ref<MDtItem | undefined>(undefined)
93
+ const dialogItemIndex = ref<MDtItemIndex | undefined>()
94
+ const dialogErrors = ref<any>({})
95
+ const resetDialogs = () => {
96
+ filterDialogModel.value = !1
97
+ showDialogModel.value = !1
98
+ formDialogModel.value = !1
99
+ isUpdateDialog.value = !1
100
+ dialogItem.value = undefined
101
+ dialogItemIndex.value = undefined
102
+ dialogErrors.value = {}
103
+ }
104
+
105
+ const getHeaders = computed<any[]>(() => parseHeaders(props.headers as MDtHeadersParameter,
106
+ { noSort: props.imageColumns }) || [])
107
+ const visibleHeaders = ref<string[]>([])
108
+
109
+ const contextmenu = ref(!1)
110
+ const selected = ref<MDtItem[]>([])
111
+ const onUpdateSelectedItems = () => {
112
+ if (contextmenu.value) {
113
+ contextmenu.value = !1
114
+ }
115
+ }
116
+
117
+ const meta = ref<MDatatableMetaServer>({ ...initMetaServer })
118
+ const pagination = ref<MDatatablePagination>({ ...initPaginationOptions })
119
+ const search = ref<string | null>(null)
120
+ const searchColumnsRef = ref<string[]>([])
121
+ const searchPlaceholder = computed<string>(() => {
122
+ if (searchColumnsRef.value.length > 0) {
123
+ return __('myth.datatable.searchInputPlaceholder',
124
+ {
125
+ v: getHeaders.value.filter(e => e?.field !== props.controlKey && searchColumnsRef.value.indexOf(e.name) !== -1)
126
+ .map(e => e.label)
127
+ .join(', ')
128
+ })
129
+ }
130
+ return 'myth.datatable.searchInput'
131
+ })
132
+ const loading = ref<boolean>(!1)
133
+ const filterForm = ref<MDatatableFilterForm>({})
134
+ const tempFilterForm = ref<MDatatableFilterForm>({})
135
+ const hasAction = ref<boolean>(!1)
136
+ const fullscreen = ref(!1)
137
+
138
+ const hasAddBtn = computed<boolean>(() => {
139
+ if (props.hideAddBtn) {
140
+ return !1
141
+ }
142
+ return !!slots.form || !!props.storeRoute
143
+ })
144
+ const hasUpdateBtn = computed<boolean>(() => {
145
+ if (props.hideUpdateBtn) {
146
+ return !1
147
+ }
148
+ return (!!slots.form || !!props.updateRoute || props.updateQueryParams) as boolean
149
+ })
150
+ const hasCloneBtn = computed<boolean>(() => Boolean(props.cloneBtn))
151
+ const hasShowBtn = computed<boolean>(() => {
152
+ if (props.hideShowBtn) {
153
+ return !1
154
+ }
155
+ return (!!slots.show || !!props.showRoute || props.showQueryParams) as boolean
156
+ })
157
+ const hasDestroyBtn = computed<boolean>(() => !props.hideDestroyBtn)
158
+ const hasFilterDialog = computed<boolean>(() => !!slots.filter)
159
+
160
+ const isUpdateMode = ref<boolean>(!1)
161
+ const formMode = computed<'update' | 'store'>(() => isUpdateMode.value ? 'update' : 'store')
162
+ const isSingleSelectedItem = computed<boolean>(() => selected.value.length === 1)
163
+ const firstSelectedItem = computed<MDtItem>(() => selected.value[0] as MDtItem)
164
+ const hasSelectedItem = computed<boolean>(() => selected.value.length > 0)
165
+ const getShowTitle = computed(() => {
166
+ if (serviceName.value && typeof serviceName.value !== 'function') {
167
+ const c = pascalCase(pluralize(serviceName.value.split('/').pop()))
168
+ return __('replace.show_details', { name: __(`choice.${c}`, 1) })
169
+ }
170
+ return __('show_details')
171
+ })
172
+ const getFormTitle = computed(() => {
173
+ const name = serviceName.value && typeof serviceName.value !== 'function' ? __(`choice.${pascalCase(pluralize(
174
+ serviceName.value.split(
175
+ '/').pop()))}`, 1) : ''
176
+ return __(`replace.${formMode.value}`, { name })
177
+ })
178
+ const isGrid = computed(() => {
179
+ if (props.grid !== undefined) {
180
+ return props.grid
181
+ }
182
+ return $q.screen.lt.md
183
+ })
184
+
185
+ const getMythApiServicesSchema = (): MDtMythApiServicesSchema => {
186
+ if (typeof serviceName.value === 'function') {
187
+ return serviceName.value() as MDtMythApiServicesSchema
188
+ }
189
+ const c = api.value.services[serviceName.value]
190
+ if (!c) {
191
+ throw Error(`No Service: ${serviceName.value}`)
192
+ }
193
+ return c
194
+ }
195
+ const updateSelectedItems = (items: MDtItem[]) => {
196
+ selected.value = items as any
197
+ }
198
+ const onScroll = ({ index, to }: any) => {
199
+ if (index && to && index === to) {
200
+ loadMore()
201
+ }
202
+ }
203
+ const loadMore = () => {
204
+ nextTick(() => {
205
+ fetchDatatableItems({
206
+ pagination: {
207
+ ...pagination.value,
208
+ page: (pagination.value.page ?? 0) + 1
209
+ },
210
+ filter: search.value
211
+ })
212
+ })
213
+ }
214
+ const refreshNoUpdate = (done?: () => void) => {
215
+ if (contextmenu.value) {
216
+ contextmenu.value = !1
217
+ }
218
+ meta.value = { ...initMetaServer }
219
+ pagination.value.page = 1
220
+ pagination.value.rowsNumber = 0
221
+ getRows.value = []
222
+ nextTick(() => {
223
+ fetchDatatableItems({
224
+ pagination: pagination.value,
225
+ filter: search.value
226
+ })
227
+ if (done) {
228
+ done()
229
+ }
230
+ })
231
+ }
232
+ const refresh = (done?: () => void) => refreshNoUpdate(done)
233
+ const getRequestWith = (type: 'withIndex' | 'withShow' | 'withUpdate' | 'withStore'): string | null => {
234
+ let v: any = []
235
+ const params: { [k: string]: string } & string | (() => string | object) = props[type] as any
236
+ if (params) {
237
+ if (typeof params === 'string') {
238
+ v = params.split(',')
239
+ }
240
+
241
+ if (lodash.isArray(params)) {
242
+ v = [...params]
243
+ } else if (lodash.isObject(params) && typeof params !== 'function') {
244
+ let e
245
+ for (const k in params) {
246
+ e = params[k]
247
+ v.push(`${k}=${e}`)
248
+ }
249
+ } else if (lodash.isFunction(params)) {
250
+ const f = params()
251
+ v = typeof f === 'string' ? f.split(',') : f
252
+ }
253
+ }
254
+ return v.join(',') ?? null
255
+ }
256
+ const getDatatableParams = ({
257
+ pagination,
258
+ filter
259
+ }: FetchRowsArgs = {}, merge: Partial<ApiServiceParams> = {}): ApiServiceParams => {
260
+ const headerItems = getHeaders.value.map((e: any) => e.name).join(',')
261
+ // console.log(headerItems)
262
+ let params: ApiServiceParams = {
263
+ headerItems,
264
+ indexType: 'index',
265
+ fdt: 'i',
266
+ itemsPerPage: pagination?.rowsPerPage === 0 ? -1 : (pagination?.rowsPerPage !== undefined ? pagination?.rowsPerPage : 0),
267
+ page: pagination?.page !== undefined ? pagination.page : 0,
268
+ sortBy: pagination?.sortBy !== undefined ? pagination.sortBy : undefined,
269
+ sortDesc: !pagination?.sortBy ? undefined : (pagination?.descending === !0 ? 1 : (pagination?.descending === !1 ? 0 : undefined))
270
+ }
271
+ if (filter) {
272
+ params.search = filter
273
+ }
274
+ if (Object.keys(filterForm.value).length > 0) {
275
+ const TempFilter = { ...filterForm.value } as any
276
+ for (const fKey in TempFilter) {
277
+ if (lodash.isArray(TempFilter[fKey])) {
278
+ TempFilter[fKey] = TempFilter[fKey].map((elm: any) => {
279
+ if (elm.id) {
280
+ return elm.id
281
+ } else if (elm.value) {
282
+ return elm.value
283
+ }
284
+ return elm
285
+ })
286
+ } else if (lodash.isPlainObject(TempFilter[fKey])) {
287
+ if (TempFilter[fKey].id) {
288
+ TempFilter[fKey] = TempFilter[fKey].id
289
+ } else if (TempFilter[fKey].value) {
290
+ TempFilter[fKey] = TempFilter[fKey].value
291
+ }
292
+ }
293
+ }
294
+ // console.log(JSON.stringify(filterForm.value))
295
+ // params.filter = filterForm.value
296
+ // console.log(TempFilter)
297
+ params.filter = TempFilter
298
+ }
299
+ if (searchColumnsRef.value.length > 0) {
300
+ params.searchColumns = searchColumnsRef.value.join(',')
301
+ }
302
+ if (props.requestParams) {
303
+ if (typeof props.requestParams === 'function') {
304
+ params = props.requestParams(params) as ApiServiceParams
305
+ } else {
306
+ params = {
307
+ ...params,
308
+ ...props.requestParams
309
+ }
310
+ }
311
+ }
312
+ return { ...params, ...merge }
313
+ }
314
+ const fetchDatatableItems = (opts: FetchRowsArgs = {}) => {
315
+ if (props.endReach && meta.value.last_page && pagination.value.page >= meta.value.last_page) {
316
+ return
317
+ }
318
+ if (loading.value || !serviceName.value) return
319
+ loading.value = !0
320
+ selected.value = []
321
+ nextTick(() => {
322
+ const params = getDatatableParams(opts)
323
+ const requestWith = getRequestWith('withIndex')
324
+ if (requestWith) {
325
+ params.requestWith = requestWith
326
+ }
327
+ // console.log({ params })
328
+ getMythApiServicesSchema().index({ params })
329
+ .then((result: any) => {
330
+ const { _data, _meta } = result
331
+ pagination.value = {
332
+ page: parseInt((_meta?.current_page || 1).toString()) || 1,
333
+ rowsPerPage: parseInt(_meta?.per_page) || 0,
334
+ rowsNumber: parseInt((_meta?.total || 0).toString()) || 0,
335
+ sortBy: opts?.pagination?.sortBy || undefined,
336
+ descending: opts?.pagination?.descending || undefined
337
+ }
338
+ _meta && (meta.value = _meta)
339
+ if (props.endReach) {
340
+ getRows.value = [...getRows.value, ...(_data || [])]
341
+ } else {
342
+ getRows.value = _data || []
343
+ }
344
+ })
345
+ .catch((e) => {
346
+ // console.log(e)
347
+ if (e?.response?.status === 401) {
348
+ logoutDatatable()
349
+ return e
350
+ }
351
+ if (e?._message) {
352
+ alertError(e._message)
353
+ } else if (e?.message) {
354
+ alertError(e.message)
355
+ }
356
+ })
357
+ .finally(() => {
358
+ loading.value = !1
359
+ })
360
+ })
361
+ }
362
+ const exportData = (type: MDtExportOptions) => {
363
+ if (loading.value) {
364
+ return
365
+ }
366
+ const ex = async () => {
367
+ loading.value = !0
368
+ const toBLob = exportToBlob.value === !0 || exportToBlob.value === type
369
+ const headerItems = getHeaders.value.filter(e => e?.field !== props.controlKey && visibleHeaders.value.indexOf(e.name) !== -1)
370
+ const data = getDatatableParams({
371
+ pagination: pagination.value,
372
+ filter: search.value
373
+ }, {
374
+ indexType: type,
375
+ fdt: 'e',
376
+ toUrl: toBLob === !0 ? !1 : exportToBlob.value !== type,
377
+ headerItems
378
+ })
379
+ if (selected.value.length > 0) {
380
+ data.ids = selected.value.map((e: any) => e.id)
381
+ }
382
+ // console.log(3)
383
+ const config: AxiosRequestConfig = {}
384
+ if (toBLob) {
385
+ config.responseType = 'blob'
386
+ }
387
+ getMythApiServicesSchema().export(data, config)
388
+ .then(async (response) => {
389
+ const { _message } = response || {}
390
+ _message && (alertSuccess(_message))
391
+ try {
392
+ await downloadFromResponse(response)
393
+ } catch (e: any) {
394
+ if (response.status === 200 && response.headers['content-type'] === 'application/json') {
395
+ return response
396
+ }
397
+ if (e?.code) {
398
+ alertError(__(`messages.${e.code}`))
399
+ } else if (e?.message) {
400
+ alertError(e.message)
401
+ }
402
+ console.log(e)
403
+ }
404
+ return response
405
+ })
406
+ .catch((e) => {
407
+ alertError(e?._message || e?.message || 'Error')
408
+ })
409
+ .finally(() => {
410
+ loading.value = !1
411
+ })
412
+ }
413
+ if (!selected.value.length) {
414
+ confirmMessage(__('messages.export_all')).onOk(() => ex())
415
+ } else {
416
+ ex()
417
+ }
418
+ }
419
+ const openDialogTimeout = 100
420
+ const setValues = useSetFormValues()
421
+ const resetDialogForm = useResetForm()
422
+ const resetVeeForm = async (attrs?: Record<string, any>) => {
423
+ const init: any = {}
424
+ for (const k in props.defaultItem) {
425
+ init[k] = attrs && k in attrs ? attrs[k] : props.defaultItem[k]
426
+ }
427
+ resetDialogForm({ values: init || {} }, { force: !0 })
428
+ attrs && setValues(attrs, !1)
429
+ }
430
+ const openFilterDialog = () => {
431
+ resetDialogForm({ values: {}, errors: {} }, { force: !0 })
432
+ nextTick(() => {
433
+ tempFilterForm.value = { ...filterForm.value }
434
+ filterDialogModel.value = !0
435
+ })
436
+ }
437
+ const saveFilterDialog = () => {
438
+ filterDialogModel.value = !1
439
+ nextTick(() => (filterForm.value = { ...tempFilterForm.value }))
440
+ }
441
+ const closeFilterDialog = () => {
442
+ filterDialogModel.value = !1
443
+ tempFilterForm.value = { ...filterForm.value }
444
+ }
445
+ const onRemoveFilter = (key: string | number) => {
446
+ const filter = filterForm.value
447
+ delete filter[key]
448
+ filterForm.value = { ...filter }
449
+ if (route.query[key]) {
450
+ const query = { ...route.query }
451
+ delete query[key]
452
+ router.push({ query })
453
+ }
454
+ }
455
+ const updateFilterOptions = (data: Record<string, any>) => {
456
+ filterForm.value = {
457
+ ...filterForm.value,
458
+ ...data
459
+ }
460
+ }
461
+
462
+ const openShowDialogNoIndex = async (i: MDtItem) => {
463
+ const item = toRef(i)
464
+ const index = getRows.value.findIndex(e => e.id === item.value.id)
465
+ return openShowDialog(item.value, index)
466
+ }
467
+ const openShowDialog = async (i: MDtItem, index: MDtItemIndex) => {
468
+ const fdt = 's'
469
+ const item = toRef(i)
470
+ if (props.showQueryParams) {
471
+ router.push({ query: { ...route.query, id: item.value.id, fdt } })
472
+ return
473
+ }
474
+ if (props.showRoute) {
475
+ if (typeof props.showRoute === 'string') {
476
+ router.push({ name: props.showRoute, params: { id: item.value.id }, query: route.query })
477
+ } else {
478
+ router.push(props.showRoute)
479
+ }
480
+ return
481
+ }
482
+ if (loading.value) {
483
+ return
484
+ }
485
+ loading.value = !0
486
+ const params: any = { fdt }
487
+ if (getRequestWith('withShow')) {
488
+ params.requestWith = getRequestWith('withShow')
489
+ }
490
+
491
+ getMythApiServicesSchema().show(item.value.id, { params })
492
+ .then(({ _data }) => {
493
+ dialogItem.value = _data
494
+ dialogItemIndex.value = index
495
+ getRows.value[index as any] = _data as any
496
+ nextTick(() => setTimeout(() => (selected.value = [getRows.value[index] as any]), openDialogTimeout))
497
+ setTimeout(() => (showDialogModel.value = !0), openDialogTimeout)
498
+ })
499
+ .catch((e: any) => {
500
+ const message = e?._message || e?.message
501
+ message && alertError(message)
502
+ })
503
+ .finally(() => (loading.value = !1))
504
+ }
505
+ const closeShowDialog = () => {
506
+ showDialogModel.value = !1
507
+ dialogItem.value = undefined
508
+ dialogItemIndex.value = undefined
509
+ }
510
+
511
+ const updateRouteProp = computed(() => props.updateRoute)
512
+ const openUpdateDialogNoIndex = (i: MDtItem) => {
513
+ const item = toRef(i)
514
+ const index = getRows.value.findIndex(e => e.id === item.value.id)
515
+ return openUpdateDialog(item.value, index)
516
+ }
517
+ const openUpdateDialog = (i: MDtItem, index: MDtItemIndex) => {
518
+ const fdt = 'u'
519
+ const item = { ...toValue(i) }
520
+ if (props.updateQueryParams) {
521
+ router.push({ query: { ...route.query, id: item.id, fdt } })
522
+ return
523
+ }
524
+ if (updateRouteProp.value) {
525
+ if (typeof updateRouteProp.value === 'string') {
526
+ router.push({ name: updateRouteProp.value, params: { id: item.id }, query: route.query })
527
+ } else {
528
+ router.push(updateRouteProp.value)
529
+ }
530
+ return
531
+ }
532
+ if (loading.value) {
533
+ return
534
+ }
535
+ loading.value = !0
536
+ isUpdateMode.value = !0
537
+ const params: any = { fdt }
538
+ if (getRequestWith('withUpdate')) {
539
+ params.requestWith = getRequestWith('withUpdate')
540
+ }
541
+ getMythApiServicesSchema().show(item.id, { params })
542
+ .then(({ _data }) => {
543
+ dialogItem.value = _data
544
+ dialogItemIndex.value = index
545
+ if (_data) {
546
+ getRows.value[index] = { ..._data } as any
547
+ nextTick(() => setTimeout(() => (selected.value = [getRows.value[index] as any]), openDialogTimeout))
548
+ }
549
+ setTimeout(() => {
550
+ resetVeeForm(_data)
551
+ nextTick(() => {
552
+ formDialogModel.value = !0
553
+ })
554
+ }, openDialogTimeout)
555
+ })
556
+ .catch((e: any) => {
557
+ const message = e?._message || e?.message
558
+ message && alertError(message)
559
+ })
560
+ .finally(() => (loading.value = !1))
561
+ }
562
+ const openCreateDialog = (dtItem?: MDtItem) => {
563
+ const fdt = 'c'
564
+ if (props.storeQueryParams) {
565
+ router.push({ query: { ...route.query, id: undefined, fdt } })
566
+ return
567
+ }
568
+ if (props.storeRoute) {
569
+ if (typeof props.storeRoute === 'string') {
570
+ router.push({ name: props.storeRoute, query: route.query })
571
+ } else {
572
+ router.push(props.storeRoute)
573
+ }
574
+ return
575
+ }
576
+ isUpdateMode.value = !1
577
+ dialogItem.value = { ...defaultItem.value, ...dtItem } as MDtItem
578
+ dialogItemIndex.value = undefined
579
+ setTimeout(() => {
580
+ resetVeeForm(dtItem)
581
+ formDialogModel.value = !0
582
+ }, openDialogTimeout)
583
+ }
584
+ const closeFormDialog = () => {
585
+ formDialogModel.value = !1
586
+ isUpdateMode.value = !1
587
+ dialogItem.value = undefined
588
+ dialogItemIndex.value = undefined
589
+ setTimeout(() => resetVeeForm(), openDialogTimeout)
590
+ }
591
+
592
+ const updateDatatableItem = (i: MDtItem, index?: MDtItemIndex) => {
593
+ const item = { ...toValue(i) }
594
+ if (item) {
595
+ if (index !== undefined) {
596
+ getRows.value[index] = item
597
+ } else {
598
+ const findIndex = getRows.value.findIndex(e => parseInt(e.id?.toString?.() ?? '') === parseInt(item?.id?.toString?.() ?? ''))
599
+ if (findIndex >= 0) {
600
+ getRows.value[findIndex] = item
601
+ }
602
+ }
603
+ selected.value.length === 1 && updateSelectedItems([item])
604
+ }
605
+ }
606
+ const removeDtItem = (i: MDtItem | number) => {
607
+ const item = toRef<MDtItem | number>(i)
608
+ const id: string | number = typeof item.value !== 'object' ? item.value : item.value.id as string
609
+ if (typeof item.value !== 'object') {
610
+ getRows.value = getRows.value.filter((e, i) => i !== id)
611
+ } else {
612
+ getRows.value = getRows.value.filter((e) => parseInt(e.id?.toString() ?? '') !== parseInt(id.toString()))
613
+ }
614
+ }
615
+ const ignoreKeysProps = computed(() => props.ignoreKeys)
616
+
617
+ const hideAutoMessage = computed(() => props.hideAutoMessage)
618
+ const onDeleteItem = (i: MDtItem, index: number) => {
619
+ const item = toRef(i)
620
+ if (loading.value || !item.value?.id) {
621
+ return
622
+ }
623
+ hasAction.value = !0
624
+ confirmMessage(__('messages.confirm_delete')).onOk(async () => {
625
+ loading.value = !0
626
+ try {
627
+ const { _message, _success } = await getMythApiServicesSchema().destroy(item.value.id)
628
+ if (!hideAutoMessage.value && _success && _message) {
629
+ _message && alertSuccess(_message)
630
+ }
631
+ if (_success) {
632
+ if (pagination.value.rowsNumber !== undefined) {
633
+ --pagination.value.rowsNumber
634
+ selected.value = []
635
+ }
636
+ removeDtItem(index)
637
+ }
638
+ } catch (e: any) {
639
+ e?._message && alertError(e._message)
640
+ } finally {
641
+ loading.value = !1
642
+ }
643
+ }).onDismiss(() => {
644
+ hasAction.value = !1
645
+ })
646
+ }
647
+ const deleteSelectionItem = () => {
648
+ if (!selected.value.length) return
649
+ if (loading.value || !selected.value.length) {
650
+ return
651
+ }
652
+ if (selected.value.length === 1) {
653
+ const dtItem = selected.value[0] as MDtItem
654
+ const index = getRows.value.findIndex((e: any) => parseInt(e.id) === parseInt(dtItem?.id?.toString() || ''))
655
+ return onDeleteItem(dtItem, index)
656
+ }
657
+ if (!props.multiDestroy) {
658
+ return
659
+ }
660
+ hasAction.value = !0
661
+ confirmMessage(__('messages.confirm_delete')).onOk(async () => {
662
+ loading.value = !0
663
+ try {
664
+ const {
665
+ _message,
666
+ _success
667
+ } = await getMythApiServicesSchema().destroyAll(selected.value.map((e: MDtItem) => e.id))
668
+ if (!hideAutoMessage.value && _success && _message) {
669
+ _message && alertSuccess(_message)
670
+ }
671
+ if (_success) {
672
+ refresh()
673
+ }
674
+ } catch (e: any) {
675
+ e?._message && alertError(e._message)
676
+ } finally {
677
+ loading.value = !1
678
+ nextTick()
679
+ selected.value = []
680
+ }
681
+ }).onDismiss(() => {
682
+ hasAction.value = !1
683
+ })
684
+ }
685
+ const logoutDatatable = () => {
686
+ //
687
+ }
688
+ const onRowContextmenu = (e: MouseEvent | Event, row: MDtItem, index: number | undefined) => {
689
+ e.preventDefault?.()
690
+ row = toValue(row)
691
+ if (index === dialogItemIndex.value) {
692
+ selected.value = []
693
+ dialogItem.value = undefined
694
+ dialogItemIndex.value = undefined
695
+ if (contextmenu.value) {
696
+ contextmenu.value = !1
697
+ }
698
+ return
699
+ }
700
+ selected.value = [row]
701
+ dialogItem.value = row
702
+ dialogItemIndex.value = index
703
+ if (isGrid.value) {
704
+ contextmenu.value = !0
705
+ }
706
+ }
707
+ const contextmenuItems = computed<any>(() => ([
708
+ {
709
+ name: 'show',
710
+ label: pluginOptions.value?.dt?.contextmenu?.btnStyle?.showLabel ? 'labels.show' : undefined,
711
+ click: (item: MDtItem, index: MDtItemIndex) => {
712
+ openShowDialog(item, index)
713
+ },
714
+ showIf: hasShowBtn.value,
715
+ order: 100
716
+ },
717
+ {
718
+ name: 'clone',
719
+ label: pluginOptions.value?.dt?.contextmenu?.btnStyle?.showLabel ? 'labels.clone' : undefined,
720
+ click: onCloneItem,
721
+ showIf: hasCloneBtn.value,
722
+ order: 200
723
+ },
724
+ {
725
+ name: 'update',
726
+ label: pluginOptions.value?.dt?.contextmenu?.btnStyle?.showLabel ? 'labels.update' : undefined,
727
+ click: (item: MDtItem, index: MDtItemIndex) => {
728
+ openUpdateDialog(item, index)
729
+ },
730
+ showIf: hasUpdateBtn.value,
731
+ order: 300
732
+ },
733
+ {
734
+ name: 'destroy',
735
+ label: pluginOptions.value?.dt?.contextmenu?.btnStyle?.showLabel ? 'labels.destroy' : undefined,
736
+ click: (item: MDtItem, index: MDtItemIndex) => {
737
+ selected.value = [item]
738
+ onDeleteItem(item, index)
739
+ },
740
+ showIf: hasDestroyBtn.value,
741
+ attr: {
742
+ color: 'negative'
743
+ },
744
+ order: 400
745
+ },
746
+ ...(props.contextItems || [])
747
+ ].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))))
748
+ const onCloneItem = (item: MDtItem) => {
749
+ item = toValue(item)
750
+ confirmMessage()
751
+ .onOk(() => {
752
+ $q.loading.show()
753
+ getMythApiServicesSchema().clone(item.id)
754
+ .then(({ _message }) => {
755
+ _message && alertSuccess(_message)
756
+ refreshNoUpdate()
757
+ })
758
+ .catch(({ _message }) => {
759
+ _message && alertError(_message)
760
+ })
761
+ .finally(() => {
762
+ $q.loading.hide()
763
+ })
764
+ })
765
+ }
766
+ const endReach = computed<boolean>(() => Boolean(props.endReach))
767
+ const rowsPerPageOptions = computed(() => props.rowsPerPageOptions)
768
+ const getRowsPerPageOptions = computed<any[]>(() => endReach.value ? [0] : (rowsPerPageOptions.value || [0]))
769
+
770
+ const imageDialog = reactive<MDatatableScope['imageDialog']>({
771
+ value: !1,
772
+ src: undefined,
773
+ asAttachment: undefined
774
+ })
775
+ const openImageDialog = (src: string, opts?: { asAttachment?: boolean }) => {
776
+ imageDialog.src = src
777
+ imageDialog.asAttachment = opts?.asAttachment
778
+ nextTick(() => {
779
+ imageDialog.value = !0
780
+ })
781
+ }
782
+ const closeImageDialog = () => {
783
+ imageDialog.value = !1
784
+ nextTick(() => {
785
+ imageDialog.src = undefined
786
+ imageDialog.asAttachment = undefined
787
+ })
788
+ }
789
+
790
+ const tableOptions = reactive<MDatatableOptions>({
791
+ search,
792
+ loading,
793
+ pagination,
794
+ meta,
795
+ filter: filterForm,
796
+ tempFilter: tempFilterForm,
797
+ selected,
798
+ hasAction,
799
+ fullscreen,
800
+ getHeaders,
801
+ visibleHeaders
802
+ })
803
+ const datatableItemsScope = reactive({
804
+ openShowDialog,
805
+ openShowDialogNoIndex,
806
+ closeShowDialog,
807
+ openUpdateDialog,
808
+ openUpdateDialogNoIndex,
809
+ openCreateDialog,
810
+ closeFormDialog,
811
+ onDeleteItem,
812
+ refresh,
813
+ refreshNoUpdate,
814
+ tableOptions,
815
+ isSingleSelectedItem,
816
+ firstSelectedItem,
817
+ updateDatatableItem,
818
+ updateSelectedItems,
819
+ imageDialog,
820
+ openImageDialog,
821
+ closeImageDialog
822
+ })
823
+ const getShowSelection = computed<boolean | undefined>(() => {
824
+ if (props.hideSelection) {
825
+ return !1
826
+ }
827
+ return props.showSelection
828
+ })
829
+ const defaultTopBtnProps: any = {
830
+ dense: !0,
831
+ flat: !0
832
+ }
833
+ const getProp = computed<any>(() => (k: any) => {
834
+ if (props[k] !== undefined) {
835
+ return props[k]
836
+ }
837
+ if (pluginOptions.value.datatable?.[k as any] !== undefined) {
838
+ return pluginOptions.value.datatable?.[k as any] as any
839
+ }
840
+ return props[k]
841
+ })
842
+ const skipSlots = ['default', 'top', 'title']
843
+ const getSlots = computed(() => {
844
+ const keys = Object.keys(slots || {})
845
+ return keys.filter(e => !skipSlots.includes(e))
846
+ })
847
+ const onClickTopMenu = (item: any) => {
848
+ if (item.multiClick && selected.value.length > 1) {
849
+ item.multiClick(selected.value)
850
+ return
851
+ }
852
+
853
+ if (item.click) {
854
+ item.click(selected.value[0], 0)
855
+ }
856
+ }
857
+
858
+ return {
859
+ imageDialog,
860
+ onRowContextmenu,
861
+ getRowsPerPageOptions,
862
+ getShowSelection,
863
+ defaultTopBtnProps,
864
+ getProp,
865
+ getSlots,
866
+ onClickTopMenu,
867
+ getRows,
868
+ defaultItem,
869
+ getTableTitle,
870
+ serviceName,
871
+ exportToBlob,
872
+ filterDialogModel,
873
+ showDialogModel,
874
+ formDialogModel,
875
+ isUpdateDialog,
876
+ dialogItem,
877
+ dialogItemIndex,
878
+ dialogErrors,
879
+ resetDialogs,
880
+ getHeaders,
881
+ visibleHeaders,
882
+ contextmenu,
883
+ selected,
884
+ onUpdateSelectedItems,
885
+ meta,
886
+ pagination,
887
+ search,
888
+ searchColumnsRef,
889
+ searchPlaceholder,
890
+ loading,
891
+ filterForm,
892
+ tempFilterForm,
893
+ hasAction,
894
+ fullscreen,
895
+ hasAddBtn,
896
+ hasUpdateBtn,
897
+ hasCloneBtn,
898
+ hasShowBtn,
899
+ hasDestroyBtn,
900
+ hasFilterDialog,
901
+ isUpdateMode,
902
+ formMode,
903
+ isSingleSelectedItem,
904
+ firstSelectedItem,
905
+ hasSelectedItem,
906
+ getShowTitle,
907
+ getFormTitle,
908
+ isGrid,
909
+ getMythApiServicesSchema,
910
+ updateSelectedItems,
911
+ onScroll,
912
+ loadMore,
913
+ refreshNoUpdate,
914
+ refresh,
915
+ getRequestWith,
916
+ getDatatableParams,
917
+ fetchDatatableItems,
918
+ exportData,
919
+ openDialogTimeout,
920
+ openFilterDialog,
921
+ saveFilterDialog,
922
+ closeFilterDialog,
923
+ onRemoveFilter,
924
+ updateFilterOptions,
925
+ openShowDialogNoIndex,
926
+ openShowDialog,
927
+ closeShowDialog,
928
+ openUpdateDialogNoIndex,
929
+ openUpdateDialog,
930
+ openCreateDialog,
931
+ closeFormDialog,
932
+ ignoreKeysProps,
933
+ updateDatatableItem,
934
+ tableOptions,
935
+ removeDtItem,
936
+ onDeleteItem,
937
+ deleteSelectionItem,
938
+ logoutDatatable,
939
+ contextmenuItems,
940
+ datatableItemsScope,
941
+ onCloneItem,
942
+ openImageDialog,
943
+ closeImageDialog
944
+ }
945
+ }