easycomponentstools 1.0.0-dev.8 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/vcs.xml +6 -0
- package/index.html +13 -0
- package/package.json +11 -6
- package/src/components/Form/types/map/CustomMapAutoComplete.vue +1 -1
- package/src/components/Modal/EasyConfirmationModal.vue +68 -0
- package/src/components/Table/Actions/ActionBtn.vue +30 -0
- package/src/components/Table/Actions/Menu.vue +43 -0
- package/src/components/Table/ColumnValue.vue +38 -0
- package/src/components/Table/EasyTable.vue +276 -0
- package/src/components/Table/Headers/DialogColumns.vue +147 -0
- package/src/components/Table/Headers/ExportData.vue +70 -0
- package/src/components/Table/Headers/Filters.vue +219 -0
- package/src/components/Table/Headers/Headers.vue +157 -0
- package/src/composables/removeMdiSet.ts +19 -0
- package/src/composables/useDataTableExport.ts +259 -0
- package/src/composables/useHeadersStorage.ts +49 -0
- package/src/dev.ts +114 -0
- package/src/lang/el/index.ts +2 -0
- package/src/lang/el/table.ts +14 -0
- package/src/lang/en/index.ts +2 -0
- package/src/lang/en/table.ts +14 -0
- package/src/main.ts +16 -1
- package/src/scss/app.scss +13 -0
- package/vite.config.ts +5 -0
- package/dist/easyComponents.es.js +0 -35624
- package/dist/easyComponents.umd.js +0 -27
- package/dist/easycomponents.css +0 -2
- package/dist/src/components/Form/EasyForm.vue.d.ts +0 -24
- package/dist/src/components/Form/MenuActions.vue.d.ts +0 -7
- package/dist/src/components/Form/types/DatePicker.vue.d.ts +0 -16
- package/dist/src/components/Form/types/FileInput.vue.d.ts +0 -16
- package/dist/src/components/Form/types/Gallery.vue.d.ts +0 -7
- package/dist/src/components/Form/types/Input.vue.d.ts +0 -12
- package/dist/src/components/Form/types/MapAutoComplete.vue.d.ts +0 -20
- package/dist/src/components/Form/types/Number.vue.d.ts +0 -12
- package/dist/src/components/Form/types/Password.vue.d.ts +0 -12
- package/dist/src/components/Form/types/RangeDatePicker.vue.d.ts +0 -16
- package/dist/src/components/Form/types/Selects.vue.d.ts +0 -16
- package/dist/src/components/Form/types/SelectsAutoComplete.vue.d.ts +0 -16
- package/dist/src/components/Form/types/Switch.vue.d.ts +0 -16
- package/dist/src/components/Form/types/Tags.vue.d.ts +0 -16
- package/dist/src/components/Form/types/TextArea.vue.d.ts +0 -12
- package/dist/src/components/Form/types/map/CustomMapAutoComplete.vue.d.ts +0 -7
- package/dist/src/composables/useHelpers.d.ts +0 -9
- package/dist/src/composables/useMap.d.ts +0 -41
- package/dist/src/lang/el/form.d.ts +0 -5
- package/dist/src/lang/el/index.d.ts +0 -7
- package/dist/src/lang/en/form.d.ts +0 -5
- package/dist/src/lang/en/index.d.ts +0 -7
- package/dist/src/main.d.ts +0 -6
- package/dist/src/stores/useInfo.d.ts +0 -7
- package/dist/src/types/form.d.ts +0 -48
- package/dist/src/types/gallery.d.ts +0 -4
- package/dist/src/types/map.d.ts +0 -32
- package/dist/src/types/plugins.d.ts +0 -14
- package/dist/src/types/table.d.ts +0 -79
package/.idea/vcs.xml
ADDED
package/index.html
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/cineplayer.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Vite + Vue</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body style="margin: 0;padding: 0;">
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/dev.ts"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "easycomponentstools",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Easy Vue Components",
|
|
7
7
|
"keywords": [
|
|
@@ -25,12 +25,15 @@
|
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@eslint/js": "^10.0.1",
|
|
28
|
+
"@types/pdfmake": "^0.3.3",
|
|
29
|
+
"@types/sanitize-html": "^2.16.1",
|
|
28
30
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
29
31
|
"eslint": "^10.4.1",
|
|
30
32
|
"eslint-config-prettier": "^10.1.8",
|
|
31
33
|
"eslint-plugin-vue": "^10.9.1",
|
|
32
34
|
"jiti": "^2.7.0",
|
|
33
35
|
"prettier": "^3.8.3",
|
|
36
|
+
"sanitize-html": "^2.17.4",
|
|
34
37
|
"sass": "^1.100.0",
|
|
35
38
|
"sass-embedded": "^1.77.8",
|
|
36
39
|
"typescript": "^6.0.3",
|
|
@@ -40,17 +43,19 @@
|
|
|
40
43
|
"vue-tsc": "^3.3.3"
|
|
41
44
|
},
|
|
42
45
|
"peerDependencies": {
|
|
43
|
-
"vue": "^
|
|
44
|
-
"vuetify": "^4.0.8",
|
|
46
|
+
"@fawmi/vue-google-maps": "^0.9.79",
|
|
45
47
|
"pinia": "^3.0.4",
|
|
46
|
-
"
|
|
48
|
+
"vue": "^3",
|
|
49
|
+
"vuetify": "^4.0.8"
|
|
47
50
|
},
|
|
48
51
|
"dependencies": {
|
|
49
52
|
"@mdi/font": "^7.4.47",
|
|
50
|
-
"@tmcw/togeojson": "^7.1.2",
|
|
51
53
|
"@types/google.maps": "^3.65.0",
|
|
52
|
-
"
|
|
54
|
+
"json-as-xlsx": "^2.5.6",
|
|
55
|
+
"lucide-static": "^0.577.0",
|
|
53
56
|
"moment-timezone": "^0.6.2",
|
|
57
|
+
"pdfmake": "^0.3.6",
|
|
58
|
+
"print-js": "^1.6.0",
|
|
54
59
|
"vue-i18n": "^11.4.4"
|
|
55
60
|
}
|
|
56
61
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-dialog v-model="dialog" width="700" persistent>
|
|
3
|
+
<v-card>
|
|
4
|
+
<v-card-title class="text-center mt-10">
|
|
5
|
+
<v-row class="textWarning">
|
|
6
|
+
<v-col cols="4" class="d-flex justify-end">
|
|
7
|
+
<i class="icon icon-octagon-alert warning-modal"></i>
|
|
8
|
+
</v-col>
|
|
9
|
+
<v-col cols="8" class="d-flex justify-start align-center text-wrap">
|
|
10
|
+
{{ description }}
|
|
11
|
+
</v-col>
|
|
12
|
+
</v-row>
|
|
13
|
+
</v-card-title>
|
|
14
|
+
<v-card-actions class="ma-4">
|
|
15
|
+
<v-row>
|
|
16
|
+
<v-col class="d-flex justify-start">
|
|
17
|
+
<v-btn color="error" variant="flat" @click="dialog = false">
|
|
18
|
+
<i class="icon icon-x"></i> {{ cancelText }}
|
|
19
|
+
</v-btn>
|
|
20
|
+
</v-col>
|
|
21
|
+
<v-col class="d-flex justify-end">
|
|
22
|
+
<v-btn color="success" variant="flat" @click="confirm">
|
|
23
|
+
<i class="icon icon-check"></i> {{ acceptText }}
|
|
24
|
+
</v-btn>
|
|
25
|
+
</v-col>
|
|
26
|
+
</v-row>
|
|
27
|
+
</v-card-actions>
|
|
28
|
+
</v-card>
|
|
29
|
+
</v-dialog>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script setup lang="ts">
|
|
33
|
+
import { ref, Ref } from 'vue'
|
|
34
|
+
|
|
35
|
+
type propsType = {
|
|
36
|
+
description: string
|
|
37
|
+
acceptText: string
|
|
38
|
+
cancelText: string
|
|
39
|
+
}
|
|
40
|
+
defineProps<propsType>()
|
|
41
|
+
const emit = defineEmits(['onConfirm'])
|
|
42
|
+
const dialog: Ref<boolean> = ref(false)
|
|
43
|
+
const itemId: Ref<string | number> = ref('')
|
|
44
|
+
|
|
45
|
+
const open = (id: string | number) => {
|
|
46
|
+
itemId.value = id
|
|
47
|
+
dialog.value = true
|
|
48
|
+
}
|
|
49
|
+
const confirm = () => {
|
|
50
|
+
dialog.value = false
|
|
51
|
+
emit('onConfirm', itemId.value)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
defineExpose({ open })
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
<style scoped lang="scss">
|
|
58
|
+
.warning-modal {
|
|
59
|
+
font-size: 55px;
|
|
60
|
+
color: rgb(var(--v-theme-warning));
|
|
61
|
+
}
|
|
62
|
+
.textWarning {
|
|
63
|
+
.text {
|
|
64
|
+
font-size: 18px;
|
|
65
|
+
font-weight: 500;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-btn
|
|
3
|
+
v-if="typeof action.show === 'function' ? action.show(item) : true"
|
|
4
|
+
class="d-flex mr-1"
|
|
5
|
+
:color="action?.color ?? 'primary'"
|
|
6
|
+
@click="ClickActionItem"
|
|
7
|
+
>
|
|
8
|
+
<i v-if="action.icon" :class="action.icon" />
|
|
9
|
+
</v-btn>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup lang="ts">
|
|
13
|
+
import { HeaderActionDTO } from '../../../types/table'
|
|
14
|
+
|
|
15
|
+
const props = defineProps<{
|
|
16
|
+
action: HeaderActionDTO
|
|
17
|
+
item: any
|
|
18
|
+
}>()
|
|
19
|
+
const emit = defineEmits(['onDelete'])
|
|
20
|
+
|
|
21
|
+
const ClickActionItem = () => {
|
|
22
|
+
if (typeof props.action.onClick === 'function') {
|
|
23
|
+
props.action.onClick(props.item)
|
|
24
|
+
} else if (props.action.onClick === 'deletion') {
|
|
25
|
+
emit('onDelete', props.item)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<style scoped></style>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-menu v-if="typeof action.show === 'function' ? action.show(item) : true">
|
|
3
|
+
<template #activator="{ props: propsMenu }">
|
|
4
|
+
<v-btn :color="action?.color ?? 'primary'" v-bind="propsMenu">
|
|
5
|
+
{{ action?.label ?? '' }}
|
|
6
|
+
<i v-if="action?.icon" :class="action.icon"></i>
|
|
7
|
+
</v-btn>
|
|
8
|
+
</template>
|
|
9
|
+
<v-list>
|
|
10
|
+
<v-list-item
|
|
11
|
+
v-for="(itemMenu, index) in action.items"
|
|
12
|
+
v-show="typeof itemMenu.show === 'function' ? itemMenu.show(item) : true"
|
|
13
|
+
:key="index"
|
|
14
|
+
:value="index"
|
|
15
|
+
>
|
|
16
|
+
<v-list-item-title @click="ClickActionItem(itemMenu)">
|
|
17
|
+
<i v-if="itemMenu.icon" :class="itemMenu.icon" />
|
|
18
|
+
{{ itemMenu?.label ?? '-' }}
|
|
19
|
+
</v-list-item-title>
|
|
20
|
+
</v-list-item>
|
|
21
|
+
</v-list>
|
|
22
|
+
</v-menu>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup lang="ts">
|
|
26
|
+
import { HeaderActionDTO, HeaderActionMenuItemsDTO } from '../../../types/table'
|
|
27
|
+
|
|
28
|
+
const props = defineProps<{
|
|
29
|
+
action: HeaderActionDTO
|
|
30
|
+
item: any
|
|
31
|
+
}>()
|
|
32
|
+
const emit = defineEmits(['onDelete'])
|
|
33
|
+
|
|
34
|
+
const ClickActionItem = (itemMenu: HeaderActionMenuItemsDTO) => {
|
|
35
|
+
if (typeof itemMenu.onClick === 'function') {
|
|
36
|
+
itemMenu.onClick(props.item)
|
|
37
|
+
} else if (itemMenu.onClick === 'deletion') {
|
|
38
|
+
emit('onDelete', props.item)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<style scoped></style>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<component
|
|
4
|
+
:is="GetColumnValue()"
|
|
5
|
+
v-if="typeof props.header.cellRenderer === 'function'"
|
|
6
|
+
></component>
|
|
7
|
+
<span v-else v-html="GetColumnValue()" />
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
import { h } from 'vue'
|
|
13
|
+
import { HeaderDTO } from '../../types/table'
|
|
14
|
+
import sanitizeHtml from 'sanitize-html'
|
|
15
|
+
|
|
16
|
+
const props = defineProps<{
|
|
17
|
+
header: HeaderDTO
|
|
18
|
+
item: any
|
|
19
|
+
}>()
|
|
20
|
+
|
|
21
|
+
const GetColumnValue = () => {
|
|
22
|
+
let html = ''
|
|
23
|
+
if (typeof props.header.cellRenderer === 'function') {
|
|
24
|
+
const result = props.header.cellRenderer(props.item[props.header.value], props.item)
|
|
25
|
+
if (Array.isArray(result)) {
|
|
26
|
+
return h('div', {}, result)
|
|
27
|
+
}
|
|
28
|
+
return result
|
|
29
|
+
} else if (typeof props.header.valueFormatter === 'function') {
|
|
30
|
+
return props.header.valueFormatter(props.item[props.header.value], props.item)
|
|
31
|
+
} else {
|
|
32
|
+
html = props.item[props.header.value]
|
|
33
|
+
return sanitizeHtml(html)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<style scoped></style>
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-container class="maintable">
|
|
3
|
+
<Headers
|
|
4
|
+
:id="id"
|
|
5
|
+
ref="headerRef"
|
|
6
|
+
:title="props.title"
|
|
7
|
+
:headers="props.headers"
|
|
8
|
+
:advanced-filters="props.advancedFilters"
|
|
9
|
+
:hard-filters="props.hardFilters"
|
|
10
|
+
:create="api?.create"
|
|
11
|
+
:show-export-data="showExportData"
|
|
12
|
+
:multiple-hard-filters="multipleHardFilters"
|
|
13
|
+
:multiple-deletion="multipleDeletion"
|
|
14
|
+
:selected="selected"
|
|
15
|
+
@multiple-delete="multipleConfirm"
|
|
16
|
+
@headers="updateDisplayHeaders"
|
|
17
|
+
@search="search"
|
|
18
|
+
@hard-filters="updateHardFilters"
|
|
19
|
+
@loading="(v) => (loading = v)"
|
|
20
|
+
>
|
|
21
|
+
<template #moreActions>
|
|
22
|
+
<slot name="moreActions"></slot>
|
|
23
|
+
</template>
|
|
24
|
+
</Headers>
|
|
25
|
+
<VDataTableServer
|
|
26
|
+
v-model="selected"
|
|
27
|
+
v-model:page="page"
|
|
28
|
+
v-model:items-per-page="itemsPerPage"
|
|
29
|
+
:headers="displayHeaders"
|
|
30
|
+
:items="items"
|
|
31
|
+
:show-select="showSelect"
|
|
32
|
+
:loading="loading"
|
|
33
|
+
:items-length="total"
|
|
34
|
+
:items-per-page-options="itemsPerPageOptions"
|
|
35
|
+
:class="$attrs.class"
|
|
36
|
+
:style="{
|
|
37
|
+
width: typeof $attrs.width === 'string' ? $attrs.width : 'auto',
|
|
38
|
+
}"
|
|
39
|
+
:height="calcHeight"
|
|
40
|
+
fixed-header
|
|
41
|
+
@update:sort-by="updateSort"
|
|
42
|
+
@update:sort-desc="updateSort"
|
|
43
|
+
@update:items-per-page="getData"
|
|
44
|
+
@update:page="getData"
|
|
45
|
+
>
|
|
46
|
+
<!-- eslint-disable -->
|
|
47
|
+
<template #header.actions>
|
|
48
|
+
<i class="icon icon-settings" v-bind="props" style="font-size: 20px"></i>
|
|
49
|
+
</template>
|
|
50
|
+
<template v-for="header in displayHeaders" #[getSlotItem(header)]="item: any">
|
|
51
|
+
<span
|
|
52
|
+
v-if="header.type === 'actions'"
|
|
53
|
+
style="display: flex; justify-content: center"
|
|
54
|
+
>
|
|
55
|
+
<span v-for="(action, index) in header.actions" :key="index">
|
|
56
|
+
<Menu
|
|
57
|
+
v-if="action.type === 'menu'"
|
|
58
|
+
:action="action"
|
|
59
|
+
:item="item.item"
|
|
60
|
+
@onDelete="confirm_deletion?.open(item.item?.id)"
|
|
61
|
+
>
|
|
62
|
+
</Menu>
|
|
63
|
+
<ActionBtn
|
|
64
|
+
v-else
|
|
65
|
+
:action="action"
|
|
66
|
+
:item="item.item"
|
|
67
|
+
@onDelete="confirm_deletion?.open(item.item?.id)"
|
|
68
|
+
>
|
|
69
|
+
</ActionBtn>
|
|
70
|
+
</span>
|
|
71
|
+
</span>
|
|
72
|
+
<ColumnValue v-else :header="header" :item="item.item"></ColumnValue>
|
|
73
|
+
</template>
|
|
74
|
+
</VDataTableServer>
|
|
75
|
+
<EasyConfirmationModal
|
|
76
|
+
ref="confirm_deletion"
|
|
77
|
+
:description="$i18n.t('table.deletion_description')"
|
|
78
|
+
:accept-text="$i18n.t('table.yes')"
|
|
79
|
+
:cancel-text="$i18n.t('table.no')"
|
|
80
|
+
@onConfirm="deletion"
|
|
81
|
+
/>
|
|
82
|
+
<EasyConfirmationModal
|
|
83
|
+
ref="multiple_confirm_deletion"
|
|
84
|
+
:description="$i18n.t('table.multiple_deletion_description')"
|
|
85
|
+
:accept-text="$i18n.t('table.yes')"
|
|
86
|
+
:cancel-text="$i18n.t('table.no')"
|
|
87
|
+
@onConfirm="multipleDelete"
|
|
88
|
+
/>
|
|
89
|
+
</v-container>
|
|
90
|
+
</template>
|
|
91
|
+
|
|
92
|
+
<script setup lang="ts">
|
|
93
|
+
import Headers from './Headers/Headers.vue'
|
|
94
|
+
import Menu from './Actions/Menu.vue'
|
|
95
|
+
import ActionBtn from './Actions/ActionBtn.vue'
|
|
96
|
+
import ColumnValue from './ColumnValue.vue'
|
|
97
|
+
import {
|
|
98
|
+
AdvancedFiltersDTO,
|
|
99
|
+
HardFiltersDTO,
|
|
100
|
+
HeaderDTO,
|
|
101
|
+
PropsDataTableDTO,
|
|
102
|
+
SortDTO,
|
|
103
|
+
} from '../../types/table'
|
|
104
|
+
import { useI18n } from 'vue-i18n'
|
|
105
|
+
import { onBeforeMount, onMounted, ref, Ref } from 'vue'
|
|
106
|
+
import useHeadersStorage from '../../composables/useHeadersStorage'
|
|
107
|
+
import EasyConfirmationModal from '../Modal/EasyConfirmationModal.vue'
|
|
108
|
+
|
|
109
|
+
const props = withDefaults(defineProps<PropsDataTableDTO>(), {
|
|
110
|
+
showSelect: false,
|
|
111
|
+
multipleHardFilters: false,
|
|
112
|
+
multipleDeletion: false,
|
|
113
|
+
title: '',
|
|
114
|
+
hardFilters: () => [],
|
|
115
|
+
advancedFilters: () => [],
|
|
116
|
+
calcHeight: '',
|
|
117
|
+
showExportData: false,
|
|
118
|
+
})
|
|
119
|
+
const emit = defineEmits(['onLoaded', 'successDelete', 'errorDelete', 'fetchError'])
|
|
120
|
+
const $i18n = useI18n()
|
|
121
|
+
const displayHeaders: Ref<HeaderDTO[]> = ref([])
|
|
122
|
+
const itemsPerPage: Ref<number> = ref(10)
|
|
123
|
+
const page: Ref<number> = ref(1)
|
|
124
|
+
const items: Ref<any[]> = ref([])
|
|
125
|
+
const selected: Ref<any[]> = ref([])
|
|
126
|
+
const sort: Ref<SortDTO | null> = ref(null)
|
|
127
|
+
const filters: Ref<AdvancedFiltersDTO[]> = ref([])
|
|
128
|
+
const hard_filters: Ref<HardFiltersDTO[]> = ref([])
|
|
129
|
+
const total: Ref<number> = ref(0)
|
|
130
|
+
const $useHeadersStorage = useHeadersStorage()
|
|
131
|
+
const loading: Ref<boolean> = ref(false)
|
|
132
|
+
const confirm_deletion: Ref<any> = ref(null)
|
|
133
|
+
const multiple_confirm_deletion: Ref<any> = ref(null)
|
|
134
|
+
const headerRef: Ref<any> = ref(null)
|
|
135
|
+
const itemsPerPageOptions = ref([
|
|
136
|
+
{ value: 10, title: '10' },
|
|
137
|
+
{ value: 25, title: '25' },
|
|
138
|
+
{ value: 50, title: '50' },
|
|
139
|
+
{ value: 100, title: '100' },
|
|
140
|
+
])
|
|
141
|
+
|
|
142
|
+
function getSlotItem(header: HeaderDTO) {
|
|
143
|
+
return `item.${header.value}`
|
|
144
|
+
}
|
|
145
|
+
const deletion = (id: string | number) => {
|
|
146
|
+
if (!props.api?.delete) return
|
|
147
|
+
loading.value = true
|
|
148
|
+
fetch(`${props.api.delete}/${id}`, {
|
|
149
|
+
method: 'DELETE',
|
|
150
|
+
})
|
|
151
|
+
.then(async (response) => {
|
|
152
|
+
if (!response.ok) {
|
|
153
|
+
throw {
|
|
154
|
+
statusCode: response.status,
|
|
155
|
+
data: await response.json(),
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return response.json()
|
|
159
|
+
})
|
|
160
|
+
.then(() => {
|
|
161
|
+
emit('successDelete')
|
|
162
|
+
getData()
|
|
163
|
+
})
|
|
164
|
+
.catch(async (error) => emit('errorDelete', error))
|
|
165
|
+
.finally(() => (loading.value = false))
|
|
166
|
+
}
|
|
167
|
+
const multipleDelete = () => {
|
|
168
|
+
if (!props.api?.multipleDelete) return
|
|
169
|
+
loading.value = true
|
|
170
|
+
fetch(`${props.api.multipleDelete}`, {
|
|
171
|
+
method: 'DELETE',
|
|
172
|
+
body: JSON.stringify({
|
|
173
|
+
ids: selected.value,
|
|
174
|
+
}),
|
|
175
|
+
})
|
|
176
|
+
.then(async (response) => {
|
|
177
|
+
if (!response.ok) {
|
|
178
|
+
throw {
|
|
179
|
+
statusCode: response.status,
|
|
180
|
+
data: await response.json(),
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return response.json()
|
|
184
|
+
})
|
|
185
|
+
.then(() => {
|
|
186
|
+
emit('successDelete')
|
|
187
|
+
selected.value = []
|
|
188
|
+
getData()
|
|
189
|
+
})
|
|
190
|
+
.catch(async (error) => emit('errorDelete', error))
|
|
191
|
+
.finally(() => (loading.value = false))
|
|
192
|
+
}
|
|
193
|
+
const multipleConfirm = () => {
|
|
194
|
+
multiple_confirm_deletion.value?.open(0)
|
|
195
|
+
}
|
|
196
|
+
const getData = async () => {
|
|
197
|
+
loading.value = true
|
|
198
|
+
const params = new URLSearchParams({
|
|
199
|
+
sort: JSON.stringify(sort.value ?? {}),
|
|
200
|
+
filters: JSON.stringify(filters.value),
|
|
201
|
+
hard_filters: JSON.stringify(hard_filters.value),
|
|
202
|
+
page: page.value.toString(),
|
|
203
|
+
limit: itemsPerPage.value.toString(),
|
|
204
|
+
})
|
|
205
|
+
fetch(`${props.api.get}?${params}`, { method: 'GET' })
|
|
206
|
+
.then(async (response) => {
|
|
207
|
+
if (!response.ok) {
|
|
208
|
+
throw {
|
|
209
|
+
statusCode: response.status,
|
|
210
|
+
data: await response.json(),
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return response.json()
|
|
214
|
+
})
|
|
215
|
+
.then((response: any) => {
|
|
216
|
+
items.value = response.data
|
|
217
|
+
total.value = response.page.total
|
|
218
|
+
headerRef.value?.updateExportDataTotal(total.value)
|
|
219
|
+
emit('onLoaded', items.value)
|
|
220
|
+
})
|
|
221
|
+
.catch(async (error) => emit('fetchError', error))
|
|
222
|
+
.finally(() => (loading.value = false))
|
|
223
|
+
}
|
|
224
|
+
const updateSort = (options: any[]) => {
|
|
225
|
+
if (options.length !== 0) {
|
|
226
|
+
sort.value = {
|
|
227
|
+
column: options[0].key,
|
|
228
|
+
sort: options[0].order,
|
|
229
|
+
}
|
|
230
|
+
headerRef.value?.updateExportSortData(sort.value)
|
|
231
|
+
page.value = 1
|
|
232
|
+
getData()
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const updateHardFilters = (hard_filters_value: HardFiltersDTO[]) => {
|
|
236
|
+
hard_filters.value = hard_filters_value
|
|
237
|
+
page.value = 1
|
|
238
|
+
getData()
|
|
239
|
+
}
|
|
240
|
+
const search = (filters_value: AdvancedFiltersDTO[]) => {
|
|
241
|
+
filters.value = filters_value
|
|
242
|
+
page.value = 1
|
|
243
|
+
getData()
|
|
244
|
+
}
|
|
245
|
+
const updateDisplayHeaders = (headers: HeaderDTO[]) => {
|
|
246
|
+
displayHeaders.value = headers
|
|
247
|
+
getData()
|
|
248
|
+
}
|
|
249
|
+
onMounted(() => {
|
|
250
|
+
setTimeout(() => {
|
|
251
|
+
headerRef.value?.updateExportData(
|
|
252
|
+
props.api.get,
|
|
253
|
+
props.headers,
|
|
254
|
+
total.value,
|
|
255
|
+
sort.value,
|
|
256
|
+
filters.value,
|
|
257
|
+
hard_filters.value
|
|
258
|
+
)
|
|
259
|
+
}, 500)
|
|
260
|
+
})
|
|
261
|
+
onBeforeMount(() => {
|
|
262
|
+
const displayStorageHeaders: HeaderDTO[] = $useHeadersStorage.loadHeaders(
|
|
263
|
+
props.headers,
|
|
264
|
+
props.id
|
|
265
|
+
)
|
|
266
|
+
if (displayStorageHeaders.length !== 0) {
|
|
267
|
+
displayHeaders.value = displayStorageHeaders.filter((v: HeaderDTO) => !v?.hidden)
|
|
268
|
+
} else {
|
|
269
|
+
displayHeaders.value = props.headers.filter((v: HeaderDTO) => !v?.hidden)
|
|
270
|
+
}
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
defineExpose({ getData, loading })
|
|
274
|
+
</script>
|
|
275
|
+
|
|
276
|
+
<style scoped></style>
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-dialog v-model="dialog" max-width="450">
|
|
3
|
+
<template #activator="{ props }">
|
|
4
|
+
<v-btn
|
|
5
|
+
elevation="0"
|
|
6
|
+
v-bind="props"
|
|
7
|
+
style="margin-left: -14px"
|
|
8
|
+
class="text-md-body-large"
|
|
9
|
+
>
|
|
10
|
+
<i class="icon icon-columns-3 mr-1" /> {{ $i18n.t('table.columns') }}
|
|
11
|
+
</v-btn>
|
|
12
|
+
</template>
|
|
13
|
+
<v-card class="list_draggable" @mousemove="onDragMove">
|
|
14
|
+
<div
|
|
15
|
+
v-if="draggedItem"
|
|
16
|
+
class="floating-drag-item"
|
|
17
|
+
:style="`top:${mouseY}px;left:${mouseX}px`"
|
|
18
|
+
>
|
|
19
|
+
{{ draggedItem.title }}
|
|
20
|
+
</div>
|
|
21
|
+
<v-card-title>
|
|
22
|
+
<v-row>
|
|
23
|
+
<v-col cols="11">
|
|
24
|
+
{{ $i18n.t('table.columns') }}
|
|
25
|
+
</v-col>
|
|
26
|
+
<v-col cols="1" class="d-flex justify-end">
|
|
27
|
+
<i class="icon icon-x" style="cursor: pointer" @click="dialog = false"></i>
|
|
28
|
+
</v-col>
|
|
29
|
+
</v-row>
|
|
30
|
+
</v-card-title>
|
|
31
|
+
<v-card-text>
|
|
32
|
+
<v-list style="background: transparent">
|
|
33
|
+
<v-list-item
|
|
34
|
+
v-for="(header, index) in headerItems"
|
|
35
|
+
:key="index"
|
|
36
|
+
class="draggable-item"
|
|
37
|
+
@mousedown.left="onDragStart($event, header)"
|
|
38
|
+
@mouseup.left="onDrop($event, header)"
|
|
39
|
+
>
|
|
40
|
+
<v-row>
|
|
41
|
+
<v-col
|
|
42
|
+
cols="2"
|
|
43
|
+
class="d-flex justify-content-start align-items-center"
|
|
44
|
+
style="margin-top: -15px"
|
|
45
|
+
>
|
|
46
|
+
<v-switch
|
|
47
|
+
v-model="header.show"
|
|
48
|
+
hide-details
|
|
49
|
+
color="primary"
|
|
50
|
+
></v-switch>
|
|
51
|
+
</v-col>
|
|
52
|
+
<v-col cols="7" class="d-flex align-items-center">
|
|
53
|
+
{{ header.title }}
|
|
54
|
+
</v-col>
|
|
55
|
+
<v-col cols="3" class="d-flex justify-content-end align-items-center">
|
|
56
|
+
<i class="icon icon-grip-horizontal"></i>
|
|
57
|
+
</v-col>
|
|
58
|
+
</v-row>
|
|
59
|
+
</v-list-item>
|
|
60
|
+
</v-list>
|
|
61
|
+
</v-card-text>
|
|
62
|
+
<v-card-actions>
|
|
63
|
+
<v-row>
|
|
64
|
+
<v-col class="d-flex justify-start">
|
|
65
|
+
<v-btn color="error" @click="dialog = false">
|
|
66
|
+
{{ $i18n.t('table.cancel') }}
|
|
67
|
+
</v-btn>
|
|
68
|
+
</v-col>
|
|
69
|
+
<v-col class="d-flex justify-end">
|
|
70
|
+
<v-btn color="success" @click="submit">
|
|
71
|
+
{{ $i18n.t('table.submit') }}
|
|
72
|
+
</v-btn>
|
|
73
|
+
</v-col>
|
|
74
|
+
</v-row>
|
|
75
|
+
</v-card-actions>
|
|
76
|
+
</v-card>
|
|
77
|
+
</v-dialog>
|
|
78
|
+
</template>
|
|
79
|
+
|
|
80
|
+
<script setup lang="ts">
|
|
81
|
+
import { onBeforeMount, ref, Ref } from 'vue'
|
|
82
|
+
import { HeaderDTO } from '../../../types/table'
|
|
83
|
+
import { useI18n } from 'vue-i18n'
|
|
84
|
+
|
|
85
|
+
type propsType = {
|
|
86
|
+
headers: HeaderDTO[]
|
|
87
|
+
}
|
|
88
|
+
const props = defineProps<propsType>()
|
|
89
|
+
const $i18n = useI18n()
|
|
90
|
+
const emit = defineEmits(['submit'])
|
|
91
|
+
const headerItems: Ref<HeaderDTO[]> = ref([])
|
|
92
|
+
const dialog: Ref<boolean> = ref(false)
|
|
93
|
+
const mouseX: Ref<number> = ref(0)
|
|
94
|
+
const mouseY: Ref<number> = ref(0)
|
|
95
|
+
const startX: Ref<number> = ref(0)
|
|
96
|
+
const startY: Ref<number> = ref(0)
|
|
97
|
+
const offsetX: Ref<number> = ref(0)
|
|
98
|
+
const offsetY: Ref<number> = ref(0)
|
|
99
|
+
const draggedItem: Ref<HeaderDTO | null> = ref(null)
|
|
100
|
+
|
|
101
|
+
const onDragStart = (event: DragEvent, header: HeaderDTO) => {
|
|
102
|
+
startX.value = event.clientX
|
|
103
|
+
startY.value = event.clientY
|
|
104
|
+
const rect = document.querySelector('.list_draggable')?.getBoundingClientRect()
|
|
105
|
+
offsetX.value = event.clientX - (rect?.left ?? 0) - 20
|
|
106
|
+
offsetY.value = event.clientY - (rect?.top ?? 0) - 20
|
|
107
|
+
draggedItem.value = header
|
|
108
|
+
}
|
|
109
|
+
const onDrop = (event: DragEvent, targetHeader: HeaderDTO) => {
|
|
110
|
+
event.preventDefault()
|
|
111
|
+
if (draggedItem.value && draggedItem.value !== targetHeader) {
|
|
112
|
+
const targetIndex = headerItems.value.findIndex((v) => v.value === targetHeader.value)
|
|
113
|
+
const draggableIndex = headerItems.value.findIndex(
|
|
114
|
+
(v) => v.value === draggedItem.value?.value
|
|
115
|
+
)
|
|
116
|
+
if (targetIndex !== -1 && draggableIndex !== -1) {
|
|
117
|
+
headerItems.value.splice(draggableIndex, 1)
|
|
118
|
+
headerItems.value.splice(targetIndex, 0, draggedItem.value)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
draggedItem.value = null
|
|
122
|
+
}
|
|
123
|
+
const onDragMove = (event: DragEvent) => {
|
|
124
|
+
if (draggedItem.value) {
|
|
125
|
+
mouseX.value = event.clientX - startX.value + offsetX.value
|
|
126
|
+
mouseY.value = event.clientY - startY.value + offsetY.value
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const submit = () => {
|
|
130
|
+
const headers = headerItems.value.map((header) => {
|
|
131
|
+
header['hidden'] = !header?.show
|
|
132
|
+
return header
|
|
133
|
+
})
|
|
134
|
+
emit('submit', headers)
|
|
135
|
+
dialog.value = false
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
onBeforeMount(() => {
|
|
139
|
+
headerItems.value = [...props.headers]
|
|
140
|
+
headerItems.value = headerItems.value.map((header) => {
|
|
141
|
+
Object.assign(header, { show: !header?.hidden })
|
|
142
|
+
return header
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
</script>
|
|
146
|
+
|
|
147
|
+
<style scoped lang="scss"></style>
|