@finema/core 1.4.98 → 1.4.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -60
- package/dist/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/components/Alert.vue +48 -48
- package/dist/runtime/components/Avatar.vue +27 -27
- package/dist/runtime/components/Badge.vue +11 -11
- package/dist/runtime/components/Breadcrumb.vue +44 -44
- package/dist/runtime/components/Button/Group.vue +37 -37
- package/dist/runtime/components/Button/index.vue +76 -76
- package/dist/runtime/components/Card.vue +38 -38
- package/dist/runtime/components/Core.vue +13 -13
- package/dist/runtime/components/Dialog/index.vue +108 -108
- package/dist/runtime/components/Dropdown/index.vue +70 -70
- package/dist/runtime/components/FlexDeck/Base.vue +90 -90
- package/dist/runtime/components/FlexDeck/index.vue +66 -66
- package/dist/runtime/components/Form/FieldWrapper.vue +23 -23
- package/dist/runtime/components/Form/Fields.vue +177 -177
- package/dist/runtime/components/Form/InputCheckbox/index.vue +21 -21
- package/dist/runtime/components/Form/InputDateTime/index.vue +60 -60
- package/dist/runtime/components/Form/InputNumber/index.vue +27 -27
- package/dist/runtime/components/Form/InputRadio/index.vue +27 -27
- package/dist/runtime/components/Form/InputSelect/index.vue +36 -36
- package/dist/runtime/components/Form/InputStatic/index.vue +16 -16
- package/dist/runtime/components/Form/InputText/index.vue +67 -67
- package/dist/runtime/components/Form/InputTextarea/index.vue +25 -25
- package/dist/runtime/components/Form/InputToggle/index.vue +14 -14
- package/dist/runtime/components/Form/InputUploadDropzone/index.vue +206 -205
- package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue +333 -355
- package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/Item.vue +260 -283
- package/dist/runtime/components/Form/InputUploadDropzoneAutoMultiple/index.vue +140 -126
- package/dist/runtime/components/Form/InputUploadDropzoneImageAutoMultiple/index.vue +148 -134
- package/dist/runtime/components/Form/InputUploadDropzoneImageAutoMultiple/item.vue +167 -198
- package/dist/runtime/components/Form/InputUploadFileClassic/index.vue +95 -103
- package/dist/runtime/components/Form/InputUploadFileClassicAuto/index.vue +143 -178
- package/dist/runtime/components/Form/index.vue +6 -6
- package/dist/runtime/components/Icon.vue +23 -23
- package/dist/runtime/components/Image.vue +36 -36
- package/dist/runtime/components/Loader.vue +27 -27
- package/dist/runtime/components/Modal/index.vue +146 -146
- package/dist/runtime/components/QRCode.vue +1 -1
- package/dist/runtime/components/SimplePagination.vue +96 -96
- package/dist/runtime/components/Slideover/index.vue +110 -110
- package/dist/runtime/components/Table/Base.vue +139 -139
- package/dist/runtime/components/Table/ColumnDate.vue +16 -16
- package/dist/runtime/components/Table/ColumnDateTime.vue +18 -18
- package/dist/runtime/components/Table/ColumnImage.vue +15 -15
- package/dist/runtime/components/Table/ColumnNumber.vue +14 -14
- package/dist/runtime/components/Table/ColumnText.vue +25 -25
- package/dist/runtime/components/Table/Simple.vue +69 -69
- package/dist/runtime/components/Table/index.vue +65 -65
- package/dist/runtime/components/Tabs/index.vue +64 -64
- package/dist/runtime/helpers/componentHelper.d.ts +18 -8
- package/dist/runtime/helpers/componentHelper.mjs +47 -8
- package/dist/runtime/utils/ArrayHelper.spec.mjs +1 -5
- package/dist/runtime/utils/FileHelper.spec.d.ts +1 -0
- package/dist/runtime/utils/FileHelper.spec.mjs +14 -0
- package/dist/runtime/utils/ObjectHelper.spec.d.ts +1 -0
- package/dist/runtime/utils/ObjectHelper.spec.mjs +52 -0
- package/dist/runtime/utils/ParamHelper.spec.d.ts +1 -0
- package/dist/runtime/utils/ParamHelper.spec.mjs +78 -0
- package/dist/runtime/utils/StringHelper.spec.d.ts +1 -0
- package/dist/runtime/utils/StringHelper.spec.mjs +76 -0
- package/package.json +89 -89
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
<template>{{ getValue }}</template>
|
|
2
|
-
<script lang="ts" setup>
|
|
3
|
-
import { computed } from 'vue'
|
|
4
|
-
import { type IColumn } from '#core/components/Table/types'
|
|
5
|
-
import { StringHelper } from '#imports'
|
|
6
|
-
|
|
7
|
-
const props = defineProps<{
|
|
8
|
-
value: any
|
|
9
|
-
row: any
|
|
10
|
-
column: IColumn<{
|
|
11
|
-
max?: number
|
|
12
|
-
}>
|
|
13
|
-
}>()
|
|
14
|
-
|
|
15
|
-
const getValue = computed<string>(() => {
|
|
16
|
-
const value = props.value
|
|
17
|
-
const max = props.column.props?.max
|
|
18
|
-
|
|
19
|
-
if (max) {
|
|
20
|
-
return StringHelper.truncate(value, max)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return value ?? '-'
|
|
24
|
-
})
|
|
25
|
-
</script>
|
|
1
|
+
<template>{{ getValue }}</template>
|
|
2
|
+
<script lang="ts" setup>
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import { type IColumn } from '#core/components/Table/types'
|
|
5
|
+
import { StringHelper } from '#imports'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
value: any
|
|
9
|
+
row: any
|
|
10
|
+
column: IColumn<{
|
|
11
|
+
max?: number
|
|
12
|
+
}>
|
|
13
|
+
}>()
|
|
14
|
+
|
|
15
|
+
const getValue = computed<string>(() => {
|
|
16
|
+
const value = props.value
|
|
17
|
+
const max = props.column.props?.max
|
|
18
|
+
|
|
19
|
+
if (max) {
|
|
20
|
+
return StringHelper.truncate(value, max)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return value ?? '-'
|
|
24
|
+
})
|
|
25
|
+
</script>
|
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<Base
|
|
3
|
-
v-bind="$attrs"
|
|
4
|
-
:columns="options.columns"
|
|
5
|
-
:raw-data="itemsByPage"
|
|
6
|
-
:status="options.status"
|
|
7
|
-
:page-options="pageOptions"
|
|
8
|
-
:is-simple-pagination="isShowSimplePagination"
|
|
9
|
-
:is-hide-bottom-pagination="options.isHideBottomPagination"
|
|
10
|
-
@page-change="onPageChange"
|
|
11
|
-
>
|
|
12
|
-
<template v-for="(_, slot) of $slots" #[slot]="slotProps">
|
|
13
|
-
<slot :name="slot" v-bind="slotProps || {}" />
|
|
14
|
-
</template>
|
|
15
|
-
</Base>
|
|
16
|
-
</template>
|
|
17
|
-
<script lang="ts" setup>
|
|
18
|
-
import { computed, type PropType, ref } from 'vue'
|
|
19
|
-
import { type ISimpleTableOptions } from '#core/components/Table/types'
|
|
20
|
-
import Base from '#core/components/Table/Base.vue'
|
|
21
|
-
import { initPageOptions } from '#core/composables/loaderPage'
|
|
22
|
-
import { useCoreConfig } from '#core/composables/useConfig'
|
|
23
|
-
|
|
24
|
-
defineSlots<{
|
|
25
|
-
'empty-state': () => any
|
|
26
|
-
'loading-state': () => any
|
|
27
|
-
}>()
|
|
28
|
-
|
|
29
|
-
const props = defineProps({
|
|
30
|
-
options: { type: Object as PropType<ISimpleTableOptions>, required: true },
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
const currentPage = ref(1)
|
|
34
|
-
const coreConfig = useCoreConfig()
|
|
35
|
-
const isShowSimplePagination = computed(
|
|
36
|
-
(): boolean => props.options.isSimplePagination ?? coreConfig.is_simple_pagination
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
const pageOptions = computed(() => {
|
|
40
|
-
if (!props.options?.limit) {
|
|
41
|
-
return undefined
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
...initPageOptions({
|
|
46
|
-
limit: props.options.limit,
|
|
47
|
-
primary: props.options.primary,
|
|
48
|
-
}),
|
|
49
|
-
totalCount: props.options.rawData.length,
|
|
50
|
-
totalPage: Math.ceil(props.options.rawData.length / props.options.limit),
|
|
51
|
-
currentPage: currentPage.value,
|
|
52
|
-
}
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
const onPageChange = (page: number) => {
|
|
56
|
-
currentPage.value = page
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const itemsByPage = computed(() => {
|
|
60
|
-
if (!pageOptions.value) {
|
|
61
|
-
return props.options?.rawData
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const start = (pageOptions.value.currentPage - 1) * pageOptions.value.limit
|
|
65
|
-
const end = start + pageOptions.value.limit
|
|
66
|
-
|
|
67
|
-
return props.options?.rawData.slice(start, end)
|
|
68
|
-
})
|
|
69
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<Base
|
|
3
|
+
v-bind="$attrs"
|
|
4
|
+
:columns="options.columns"
|
|
5
|
+
:raw-data="itemsByPage"
|
|
6
|
+
:status="options.status"
|
|
7
|
+
:page-options="pageOptions"
|
|
8
|
+
:is-simple-pagination="isShowSimplePagination"
|
|
9
|
+
:is-hide-bottom-pagination="options.isHideBottomPagination"
|
|
10
|
+
@page-change="onPageChange"
|
|
11
|
+
>
|
|
12
|
+
<template v-for="(_, slot) of $slots" #[slot]="slotProps">
|
|
13
|
+
<slot :name="slot" v-bind="slotProps || {}" />
|
|
14
|
+
</template>
|
|
15
|
+
</Base>
|
|
16
|
+
</template>
|
|
17
|
+
<script lang="ts" setup>
|
|
18
|
+
import { computed, type PropType, ref } from 'vue'
|
|
19
|
+
import { type ISimpleTableOptions } from '#core/components/Table/types'
|
|
20
|
+
import Base from '#core/components/Table/Base.vue'
|
|
21
|
+
import { initPageOptions } from '#core/composables/loaderPage'
|
|
22
|
+
import { useCoreConfig } from '#core/composables/useConfig'
|
|
23
|
+
|
|
24
|
+
defineSlots<{
|
|
25
|
+
'empty-state': () => any
|
|
26
|
+
'loading-state': () => any
|
|
27
|
+
}>()
|
|
28
|
+
|
|
29
|
+
const props = defineProps({
|
|
30
|
+
options: { type: Object as PropType<ISimpleTableOptions>, required: true },
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const currentPage = ref(1)
|
|
34
|
+
const coreConfig = useCoreConfig()
|
|
35
|
+
const isShowSimplePagination = computed(
|
|
36
|
+
(): boolean => props.options.isSimplePagination ?? coreConfig.is_simple_pagination
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
const pageOptions = computed(() => {
|
|
40
|
+
if (!props.options?.limit) {
|
|
41
|
+
return undefined
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
...initPageOptions({
|
|
46
|
+
limit: props.options.limit,
|
|
47
|
+
primary: props.options.primary,
|
|
48
|
+
}),
|
|
49
|
+
totalCount: props.options.rawData.length,
|
|
50
|
+
totalPage: Math.ceil(props.options.rawData.length / props.options.limit),
|
|
51
|
+
currentPage: currentPage.value,
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const onPageChange = (page: number) => {
|
|
56
|
+
currentPage.value = page
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const itemsByPage = computed(() => {
|
|
60
|
+
if (!pageOptions.value) {
|
|
61
|
+
return props.options?.rawData
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const start = (pageOptions.value.currentPage - 1) * pageOptions.value.limit
|
|
65
|
+
const end = start + pageOptions.value.limit
|
|
66
|
+
|
|
67
|
+
return props.options?.rawData.slice(start, end)
|
|
68
|
+
})
|
|
69
|
+
</script>
|
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<div v-if="options.isEnabledSearch" class="mb-4 flex justify-end">
|
|
4
|
-
<UInput
|
|
5
|
-
v-model="q"
|
|
6
|
-
icon="i-heroicons-magnifying-glass"
|
|
7
|
-
:placeholder="options.searchPlaceholder || 'ค้นหา...'"
|
|
8
|
-
/>
|
|
9
|
-
</div>
|
|
10
|
-
<Base
|
|
11
|
-
v-bind="$attrs"
|
|
12
|
-
:columns="options.columns"
|
|
13
|
-
:raw-data="options.rawData"
|
|
14
|
-
:status="options.status"
|
|
15
|
-
:page-options="options.pageOptions"
|
|
16
|
-
:is-simple-pagination="isShowSimplePagination"
|
|
17
|
-
:is-hide-bottom-pagination="options.isHideBottomPagination"
|
|
18
|
-
@page-change="onPageChange"
|
|
19
|
-
>
|
|
20
|
-
<template v-for="(_, slot) of $slots" #[slot]="slotProps">
|
|
21
|
-
<slot :name="slot" v-bind="slotProps || {}" />
|
|
22
|
-
</template>
|
|
23
|
-
</Base>
|
|
24
|
-
</div>
|
|
25
|
-
</template>
|
|
26
|
-
<script lang="ts" setup>
|
|
27
|
-
import { type PropType } from 'vue'
|
|
28
|
-
import { type ITableOptions } from '#core/components/Table/types'
|
|
29
|
-
import { _debounce, computed, ref, watch } from '#imports'
|
|
30
|
-
import { useCoreConfig } from '#core/composables/useConfig'
|
|
31
|
-
import Base from '#core/components/Table/Base.vue'
|
|
32
|
-
|
|
33
|
-
defineSlots<{
|
|
34
|
-
'empty-state': () => any
|
|
35
|
-
'loading-state': () => any
|
|
36
|
-
}>()
|
|
37
|
-
|
|
38
|
-
const emits = defineEmits<{
|
|
39
|
-
(event: 'pageChange', page: number): void
|
|
40
|
-
(event: 'search', q: string): void
|
|
41
|
-
}>()
|
|
42
|
-
|
|
43
|
-
const props = defineProps({
|
|
44
|
-
options: { type: Object as PropType<ITableOptions>, required: true },
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
const coreConfig = useCoreConfig()
|
|
48
|
-
|
|
49
|
-
const q = ref(props.options?.pageOptions.search ?? '')
|
|
50
|
-
|
|
51
|
-
const isShowSimplePagination = computed(
|
|
52
|
-
(): boolean => props.options.isSimplePagination ?? coreConfig.is_simple_pagination
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
watch(
|
|
56
|
-
q,
|
|
57
|
-
_debounce((value) => {
|
|
58
|
-
emits('search', value)
|
|
59
|
-
}, 500)
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
const onPageChange = (page: number) => {
|
|
63
|
-
emits('pageChange', page)
|
|
64
|
-
}
|
|
65
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div v-if="options.isEnabledSearch" class="mb-4 flex justify-end">
|
|
4
|
+
<UInput
|
|
5
|
+
v-model="q"
|
|
6
|
+
icon="i-heroicons-magnifying-glass"
|
|
7
|
+
:placeholder="options.searchPlaceholder || 'ค้นหา...'"
|
|
8
|
+
/>
|
|
9
|
+
</div>
|
|
10
|
+
<Base
|
|
11
|
+
v-bind="$attrs"
|
|
12
|
+
:columns="options.columns"
|
|
13
|
+
:raw-data="options.rawData"
|
|
14
|
+
:status="options.status"
|
|
15
|
+
:page-options="options.pageOptions"
|
|
16
|
+
:is-simple-pagination="isShowSimplePagination"
|
|
17
|
+
:is-hide-bottom-pagination="options.isHideBottomPagination"
|
|
18
|
+
@page-change="onPageChange"
|
|
19
|
+
>
|
|
20
|
+
<template v-for="(_, slot) of $slots" #[slot]="slotProps">
|
|
21
|
+
<slot :name="slot" v-bind="slotProps || {}" />
|
|
22
|
+
</template>
|
|
23
|
+
</Base>
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|
|
26
|
+
<script lang="ts" setup>
|
|
27
|
+
import { type PropType } from 'vue'
|
|
28
|
+
import { type ITableOptions } from '#core/components/Table/types'
|
|
29
|
+
import { _debounce, computed, ref, watch } from '#imports'
|
|
30
|
+
import { useCoreConfig } from '#core/composables/useConfig'
|
|
31
|
+
import Base from '#core/components/Table/Base.vue'
|
|
32
|
+
|
|
33
|
+
defineSlots<{
|
|
34
|
+
'empty-state': () => any
|
|
35
|
+
'loading-state': () => any
|
|
36
|
+
}>()
|
|
37
|
+
|
|
38
|
+
const emits = defineEmits<{
|
|
39
|
+
(event: 'pageChange', page: number): void
|
|
40
|
+
(event: 'search', q: string): void
|
|
41
|
+
}>()
|
|
42
|
+
|
|
43
|
+
const props = defineProps({
|
|
44
|
+
options: { type: Object as PropType<ITableOptions>, required: true },
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const coreConfig = useCoreConfig()
|
|
48
|
+
|
|
49
|
+
const q = ref(props.options?.pageOptions.search ?? '')
|
|
50
|
+
|
|
51
|
+
const isShowSimplePagination = computed(
|
|
52
|
+
(): boolean => props.options.isSimplePagination ?? coreConfig.is_simple_pagination
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
watch(
|
|
56
|
+
q,
|
|
57
|
+
_debounce((value) => {
|
|
58
|
+
emits('search', value)
|
|
59
|
+
}, 500)
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
const onPageChange = (page: number) => {
|
|
63
|
+
emits('pageChange', page)
|
|
64
|
+
}
|
|
65
|
+
</script>
|
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<UTabs
|
|
3
|
-
v-bind="attrs"
|
|
4
|
-
:model-value="modelValue"
|
|
5
|
-
:class="$props.class"
|
|
6
|
-
:items="items"
|
|
7
|
-
:orientation="orientation"
|
|
8
|
-
:default-index="defaultIndex"
|
|
9
|
-
:ui="ui"
|
|
10
|
-
@change="change"
|
|
11
|
-
>
|
|
12
|
-
<template #default="{ item, index, selected }">
|
|
13
|
-
<slot name="default" :item="item" :index="index" :selected="selected" />
|
|
14
|
-
</template>
|
|
15
|
-
|
|
16
|
-
<template #item="{ item, index, selected }">
|
|
17
|
-
<slot name="item" :item="item" :index="index" :selected="selected" />
|
|
18
|
-
</template>
|
|
19
|
-
</UTabs>
|
|
20
|
-
</template>
|
|
21
|
-
|
|
22
|
-
<script setup lang="ts">
|
|
23
|
-
import { useUiConfig, type PropType, useUI, toRef } from '#imports'
|
|
24
|
-
import { tabs } from '#core/ui.config'
|
|
25
|
-
import type { Strategy, TabItem } from '#ui/types'
|
|
26
|
-
|
|
27
|
-
const config = useUiConfig<typeof tabs>(tabs, 'tabs')
|
|
28
|
-
|
|
29
|
-
const props = defineProps({
|
|
30
|
-
modelValue: {
|
|
31
|
-
type: Number,
|
|
32
|
-
default: undefined,
|
|
33
|
-
},
|
|
34
|
-
items: {
|
|
35
|
-
type: Array as PropType<TabItem[]>,
|
|
36
|
-
default: () => [],
|
|
37
|
-
},
|
|
38
|
-
orientation: {
|
|
39
|
-
type: String as PropType<'horizontal' | 'vertical'>,
|
|
40
|
-
default: 'horizontal',
|
|
41
|
-
validator: (value: string) => ['horizontal', 'vertical'].includes(value),
|
|
42
|
-
},
|
|
43
|
-
defaultIndex: {
|
|
44
|
-
type: Number,
|
|
45
|
-
default: 0,
|
|
46
|
-
},
|
|
47
|
-
class: {
|
|
48
|
-
type: [String, Object, Array] as PropType<any>,
|
|
49
|
-
default: () => '',
|
|
50
|
-
},
|
|
51
|
-
ui: {
|
|
52
|
-
type: Object as PropType<Partial<typeof config> & { strategy?: Strategy }>,
|
|
53
|
-
default: () => ({}),
|
|
54
|
-
},
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
const emits = defineEmits(['update:modelValue', 'change'])
|
|
58
|
-
|
|
59
|
-
const change = (index: number) => {
|
|
60
|
-
emits('change', index)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const { ui, attrs } = useUI('tabs', toRef(props, 'ui'), config, toRef(props, 'class'))
|
|
64
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<UTabs
|
|
3
|
+
v-bind="attrs"
|
|
4
|
+
:model-value="modelValue"
|
|
5
|
+
:class="$props.class"
|
|
6
|
+
:items="items"
|
|
7
|
+
:orientation="orientation"
|
|
8
|
+
:default-index="defaultIndex"
|
|
9
|
+
:ui="ui"
|
|
10
|
+
@change="change"
|
|
11
|
+
>
|
|
12
|
+
<template #default="{ item, index, selected }">
|
|
13
|
+
<slot name="default" :item="item" :index="index" :selected="selected" />
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<template #item="{ item, index, selected }">
|
|
17
|
+
<slot name="item" :item="item" :index="index" :selected="selected" />
|
|
18
|
+
</template>
|
|
19
|
+
</UTabs>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
import { useUiConfig, type PropType, useUI, toRef } from '#imports'
|
|
24
|
+
import { tabs } from '#core/ui.config'
|
|
25
|
+
import type { Strategy, TabItem } from '#ui/types'
|
|
26
|
+
|
|
27
|
+
const config = useUiConfig<typeof tabs>(tabs, 'tabs')
|
|
28
|
+
|
|
29
|
+
const props = defineProps({
|
|
30
|
+
modelValue: {
|
|
31
|
+
type: Number,
|
|
32
|
+
default: undefined,
|
|
33
|
+
},
|
|
34
|
+
items: {
|
|
35
|
+
type: Array as PropType<TabItem[]>,
|
|
36
|
+
default: () => [],
|
|
37
|
+
},
|
|
38
|
+
orientation: {
|
|
39
|
+
type: String as PropType<'horizontal' | 'vertical'>,
|
|
40
|
+
default: 'horizontal',
|
|
41
|
+
validator: (value: string) => ['horizontal', 'vertical'].includes(value),
|
|
42
|
+
},
|
|
43
|
+
defaultIndex: {
|
|
44
|
+
type: Number,
|
|
45
|
+
default: 0,
|
|
46
|
+
},
|
|
47
|
+
class: {
|
|
48
|
+
type: [String, Object, Array] as PropType<any>,
|
|
49
|
+
default: () => '',
|
|
50
|
+
},
|
|
51
|
+
ui: {
|
|
52
|
+
type: Object as PropType<Partial<typeof config> & { strategy?: Strategy }>,
|
|
53
|
+
default: () => ({}),
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
const emits = defineEmits(['update:modelValue', 'change'])
|
|
58
|
+
|
|
59
|
+
const change = (index: number) => {
|
|
60
|
+
emits('change', index)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const { ui, attrs } = useUI('tabs', toRef(props, 'ui'), config, toRef(props, 'class'))
|
|
64
|
+
</script>
|
|
@@ -1,13 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Ref } from 'vue';
|
|
2
|
+
export declare const checkMaxSize: (file: File, acceptFileSize?: number) => boolean;
|
|
2
3
|
export declare const checkFileType: (file: File, acceptFileType: string | string[]) => boolean;
|
|
3
4
|
export declare const generateURL: (file: File) => string;
|
|
4
5
|
export declare const isImage: (file: File) => boolean;
|
|
5
|
-
export declare const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
selectedFileSizeKb:
|
|
10
|
-
selectedFileSizeMb:
|
|
11
|
-
isSelectedFileUseMb:
|
|
6
|
+
export declare const useFileAllocate: (selectedFile: Ref<File | undefined | null>, props: {
|
|
7
|
+
accept?: string | string[];
|
|
8
|
+
maxSize?: number;
|
|
9
|
+
}) => {
|
|
10
|
+
selectedFileSizeKb: any;
|
|
11
|
+
selectedFileSizeMb: any;
|
|
12
|
+
isSelectedFileUseMb: any;
|
|
13
|
+
acceptFileSizeKb: any;
|
|
14
|
+
acceptFileSizeMb: any;
|
|
15
|
+
isAcceptFileUseMb: any;
|
|
16
|
+
acceptFile: any;
|
|
17
|
+
};
|
|
18
|
+
export declare const useFileProgress: () => {
|
|
19
|
+
percent: any;
|
|
20
|
+
onUploadProgress: (progressEvent: ProgressEvent) => void;
|
|
21
|
+
onDownloadProgress: (progressEvent: ProgressEvent) => void;
|
|
12
22
|
};
|
|
13
23
|
export declare const downloadFileFromURL: (url: string, filename?: string) => Promise<void>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { computed, ref, StringHelper } from "#imports";
|
|
2
|
+
export const checkMaxSize = (file, acceptFileSize = 0) => {
|
|
2
3
|
if (acceptFileSize) {
|
|
3
4
|
return file.size / 1e3 <= acceptFileSize;
|
|
4
5
|
}
|
|
@@ -37,14 +38,52 @@ export const generateURL = (file) => {
|
|
|
37
38
|
export const isImage = (file) => {
|
|
38
39
|
return file.type.startsWith("image/");
|
|
39
40
|
};
|
|
40
|
-
export const
|
|
41
|
+
export const useFileAllocate = (selectedFile, props) => {
|
|
42
|
+
const selectedFileSizeKb = computed(() => ((selectedFile.value?.size || 0) / 1e3).toFixed(2));
|
|
43
|
+
const selectedFileSizeMb = computed(
|
|
44
|
+
() => ((selectedFile.value?.size || 0) / 1e3 / 1e3).toFixed(2)
|
|
45
|
+
);
|
|
46
|
+
const isSelectedFileUseMb = computed(() => (selectedFile.value?.size || 0) / 1e3 > 1024);
|
|
47
|
+
const acceptFileSizeKb = computed(() => props.maxSize || 0);
|
|
48
|
+
const acceptFileSizeMb = computed(() => ((acceptFileSizeKb.value || 0) / 1024).toFixed(2));
|
|
49
|
+
const isAcceptFileUseMb = computed(() => acceptFileSizeKb.value && acceptFileSizeKb.value > 1024);
|
|
50
|
+
const acceptFile = computed(
|
|
51
|
+
() => typeof props.accept === "string" ? props.accept : props.accept?.join(",")
|
|
52
|
+
);
|
|
41
53
|
return {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
selectedFileSizeKb,
|
|
55
|
+
selectedFileSizeMb,
|
|
56
|
+
isSelectedFileUseMb,
|
|
57
|
+
acceptFileSizeKb,
|
|
58
|
+
acceptFileSizeMb,
|
|
59
|
+
isAcceptFileUseMb,
|
|
60
|
+
acceptFile
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
export const useFileProgress = () => {
|
|
64
|
+
const percent = ref(0);
|
|
65
|
+
const onUploadProgress = (progressEvent) => {
|
|
66
|
+
percent.value = parseFloat(
|
|
67
|
+
StringHelper.withFixed(
|
|
68
|
+
(Math.floor(progressEvent.loaded * 100 / progressEvent.total) || 0) * 0.8
|
|
69
|
+
)
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
const onDownloadProgress = (progressEvent) => {
|
|
73
|
+
if (progressEvent.total === 0) {
|
|
74
|
+
percent.value = 100;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
percent.value = parseFloat(
|
|
78
|
+
StringHelper.withFixed(
|
|
79
|
+
(Math.floor(progressEvent.loaded * 100 / progressEvent.total) || 0) * 0.2 + 80
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
percent,
|
|
85
|
+
onUploadProgress,
|
|
86
|
+
onDownloadProgress
|
|
48
87
|
};
|
|
49
88
|
};
|
|
50
89
|
export const downloadFileFromURL = async (url, filename) => {
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { describe, test, expect, vi } from "vitest";
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
3
2
|
import { ArrayHelper } from "./ArrayHelper.mjs";
|
|
4
|
-
vi.mock("#build/imports", () => ({
|
|
5
|
-
_get: get
|
|
6
|
-
}));
|
|
7
3
|
describe("ArrayHelper", () => {
|
|
8
4
|
test("toOptions default attr", () => {
|
|
9
5
|
const data = [
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { FileHelper } from "./FileHelper.mjs";
|
|
3
|
+
describe("FileHelper", () => {
|
|
4
|
+
describe("dataURLtoFile", () => {
|
|
5
|
+
it("should convert a data URL to a File", async () => {
|
|
6
|
+
const dataUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==";
|
|
7
|
+
const filename = "test.png";
|
|
8
|
+
const file = await FileHelper.dataURLtoFile(dataUrl, filename);
|
|
9
|
+
expect(file).toBeInstanceOf(File);
|
|
10
|
+
expect(file.name).toBe(filename);
|
|
11
|
+
expect(file.type).toBe("image/png");
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { ObjectHelper } from "./ObjectHelper.mjs";
|
|
3
|
+
describe("ObjectHelper", () => {
|
|
4
|
+
describe("createOption", () => {
|
|
5
|
+
it("should create an option object with the provided value and label", () => {
|
|
6
|
+
const value = "value1";
|
|
7
|
+
const label = "Label 1";
|
|
8
|
+
const option = ObjectHelper.createOption(value, label);
|
|
9
|
+
expect(option).toEqual({ value, label });
|
|
10
|
+
});
|
|
11
|
+
it("should create an option object with an empty label if not provided", () => {
|
|
12
|
+
const value = "value1";
|
|
13
|
+
const option = ObjectHelper.createOption(value);
|
|
14
|
+
expect(option).toEqual({ value, label: "" });
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
describe("toOption", () => {
|
|
18
|
+
it("should create an option object from the provided data", () => {
|
|
19
|
+
const data = { id: 1, name: "Option 1" };
|
|
20
|
+
const option = ObjectHelper.toOption(data);
|
|
21
|
+
expect(option).toEqual({ value: 1, label: "Option 1" });
|
|
22
|
+
});
|
|
23
|
+
it("should use the provided value and label attributes", () => {
|
|
24
|
+
const data = { code: "CODE1", description: "Description 1" };
|
|
25
|
+
const option = ObjectHelper.toOption(data, "code", "description");
|
|
26
|
+
expect(option).toEqual({ value: "CODE1", label: "Description 1" });
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe("toErrorStatus", () => {
|
|
30
|
+
it("should create an error status object from the provided error", () => {
|
|
31
|
+
const error = {
|
|
32
|
+
response: {
|
|
33
|
+
status: 400,
|
|
34
|
+
request: {
|
|
35
|
+
response: JSON.stringify({ code: "INVALID_REQUEST", message: "Invalid request" })
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const status = ObjectHelper.toErrorStatus({}, error);
|
|
40
|
+
expect(status.isError).toBe(true);
|
|
41
|
+
expect(status.isSuccess).toBe(false);
|
|
42
|
+
expect(status.errorData).toEqual({ code: "INVALID_REQUEST", message: "Invalid request" });
|
|
43
|
+
});
|
|
44
|
+
it("should create a network error status if the error response status is missing", () => {
|
|
45
|
+
const error = {};
|
|
46
|
+
const status = ObjectHelper.toErrorStatus({}, error);
|
|
47
|
+
expect(status.isError).toBe(true);
|
|
48
|
+
expect(status.isSuccess).toBe(false);
|
|
49
|
+
expect(status.errorData).toEqual({ code: "NETWORK_ERROR", message: "Network error" });
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|