@finema/core 1.4.90 → 1.4.91
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 +63 -63
- package/dist/module.json +1 -1
- package/dist/module.mjs +3 -2
- package/dist/runtime/components/Alert.vue +48 -48
- package/dist/runtime/components/Avatar.vue +27 -27
- package/dist/runtime/components/Badge.vue +53 -53
- 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 +160 -160
- 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 +213 -158
- package/dist/runtime/components/Form/InputUploadDropzoneAuto/index.vue +349 -243
- package/dist/runtime/components/Form/InputUploadDropzoneAuto/types.d.ts +3 -0
- package/dist/runtime/components/Form/InputUploadFileClassic/index.vue +101 -101
- package/dist/runtime/components/Form/InputUploadFileClassicAuto/index.vue +174 -174
- 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/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 +9 -0
- package/dist/runtime/helpers/componentHelper.mjs +30 -0
- package/dist/runtime/ui.config/uploadFileDropzone.d.ts +36 -13
- package/dist/runtime/ui.config/uploadFileDropzone.mjs +42 -19
- package/dist/runtime/utils/StringHelper.d.ts +1 -0
- package/dist/runtime/utils/StringHelper.mjs +6 -0
- package/package.json +88 -88
|
@@ -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>
|
|
@@ -2,3 +2,12 @@ export declare const checkMaxSize: (file: File, acceptFileSize: number) => boole
|
|
|
2
2
|
export declare const checkFileType: (file: File, acceptFileType: string | string[]) => boolean;
|
|
3
3
|
export declare const generateURL: (file: File) => string;
|
|
4
4
|
export declare const isImage: (file: File) => boolean;
|
|
5
|
+
export declare const getFileAllocate: (maxSize: number, selectedFileSize: Blob['size']) => {
|
|
6
|
+
acceptFileSizeKb: number;
|
|
7
|
+
acceptFileSizeMb: string;
|
|
8
|
+
isAcceptFileUseMb: boolean;
|
|
9
|
+
selectedFileSizeKb: string;
|
|
10
|
+
selectedFileSizeMb: string;
|
|
11
|
+
isSelectedFileUseMb: boolean;
|
|
12
|
+
};
|
|
13
|
+
export declare const downloadFileFromURL: (url: string, filename?: string) => Promise<void>;
|
|
@@ -37,3 +37,33 @@ export const generateURL = (file) => {
|
|
|
37
37
|
export const isImage = (file) => {
|
|
38
38
|
return file.type.startsWith("image/");
|
|
39
39
|
};
|
|
40
|
+
export const getFileAllocate = (maxSize, selectedFileSize) => {
|
|
41
|
+
return {
|
|
42
|
+
acceptFileSizeKb: maxSize,
|
|
43
|
+
acceptFileSizeMb: (maxSize / 1024).toFixed(2),
|
|
44
|
+
isAcceptFileUseMb: maxSize > 1024,
|
|
45
|
+
selectedFileSizeKb: (selectedFileSize / 1e3).toFixed(2),
|
|
46
|
+
selectedFileSizeMb: (selectedFileSize / 1e3 / 1e3).toFixed(2),
|
|
47
|
+
isSelectedFileUseMb: selectedFileSize / 1e3 > 1024
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export const downloadFileFromURL = async (url, filename) => {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
const xhr = new XMLHttpRequest();
|
|
53
|
+
xhr.responseType = "blob";
|
|
54
|
+
xhr.onload = () => {
|
|
55
|
+
const a = document.createElement("a");
|
|
56
|
+
const url2 = window.URL.createObjectURL(xhr.response);
|
|
57
|
+
a.href = url2;
|
|
58
|
+
a.download = filename || url2.split("/").pop() || (/* @__PURE__ */ new Date()).toISOString();
|
|
59
|
+
a.click();
|
|
60
|
+
window.URL.revokeObjectURL(url2);
|
|
61
|
+
resolve();
|
|
62
|
+
};
|
|
63
|
+
xhr.onerror = () => {
|
|
64
|
+
reject();
|
|
65
|
+
};
|
|
66
|
+
xhr.open("GET", url);
|
|
67
|
+
xhr.send();
|
|
68
|
+
});
|
|
69
|
+
};
|
|
@@ -2,33 +2,56 @@ export declare const uploadFileDropzone: {
|
|
|
2
2
|
base: string;
|
|
3
3
|
wrapper: string;
|
|
4
4
|
disabled: string;
|
|
5
|
+
failed: string;
|
|
5
6
|
placeholderWrapper: string;
|
|
6
7
|
placeholder: string;
|
|
7
8
|
labelWrapper: string;
|
|
8
|
-
|
|
9
|
+
onLoading: {
|
|
9
10
|
wrapper: string;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
placeholderWrapper: string;
|
|
12
|
+
placeholderImgIcon: string;
|
|
13
|
+
placeholderFileIcon: string;
|
|
14
|
+
placeholderIconClass: string;
|
|
15
|
+
textWrapper: string;
|
|
16
|
+
loadingIcon: string;
|
|
17
|
+
loadingIconClass: string;
|
|
16
18
|
};
|
|
17
|
-
|
|
19
|
+
onPreview: {
|
|
18
20
|
wrapper: string;
|
|
19
|
-
|
|
21
|
+
previewImgWrapper: string;
|
|
22
|
+
previewImgClass: string;
|
|
23
|
+
previewFileIcon: string;
|
|
24
|
+
previewFileClass: string;
|
|
25
|
+
textWrapper: string;
|
|
26
|
+
};
|
|
27
|
+
onFailed: {
|
|
28
|
+
wrapper: string;
|
|
29
|
+
failedImgWrapper: string;
|
|
30
|
+
failedImgIcon: string;
|
|
31
|
+
failedFileIcon: string;
|
|
32
|
+
failedIconClass: string;
|
|
33
|
+
textWrapper: string;
|
|
34
|
+
};
|
|
35
|
+
action: {
|
|
36
|
+
wrapper: string;
|
|
37
|
+
iconClass: string;
|
|
38
|
+
deleteIconClass: string;
|
|
39
|
+
retryBtnClass: string;
|
|
40
|
+
previewIcon: string;
|
|
41
|
+
downloadIcon: string;
|
|
42
|
+
deleteIcon: string;
|
|
43
|
+
retryIcon: string;
|
|
20
44
|
};
|
|
21
45
|
background: {
|
|
22
46
|
default: string;
|
|
23
47
|
dragover: string;
|
|
24
48
|
};
|
|
25
|
-
button: {
|
|
26
|
-
delete: string;
|
|
27
|
-
};
|
|
28
49
|
labelIcon: string;
|
|
29
50
|
default: {
|
|
30
|
-
closeIcon: string;
|
|
31
51
|
filePreviewIcon: string;
|
|
32
52
|
uploadIcon: string;
|
|
53
|
+
placeholderImgIcon: string;
|
|
54
|
+
failedImgIcon: string;
|
|
55
|
+
loadingIcon: string;
|
|
33
56
|
};
|
|
34
57
|
};
|
|
@@ -1,34 +1,57 @@
|
|
|
1
1
|
export const uploadFileDropzone = {
|
|
2
|
-
base: "relative w-full p-
|
|
2
|
+
base: "relative w-full p-4 transition rounded-lg flex items-center justify-center border-[1px] ring-0",
|
|
3
3
|
wrapper: "flex flex-col items-center w-full",
|
|
4
|
-
disabled: "bg-gray-
|
|
5
|
-
|
|
4
|
+
disabled: "bg-gray-100 border-none grayscale cursor-not-allowed",
|
|
5
|
+
failed: "border-danger",
|
|
6
|
+
placeholderWrapper: "py-4 flex flex-col items-center justify-center",
|
|
6
7
|
placeholder: "text-gray-400 text-center font-light text-sm truncate",
|
|
7
8
|
labelWrapper: "flex items-center space-x-2 text-gray-400 text-center",
|
|
8
|
-
|
|
9
|
-
wrapper: "
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
onLoading: {
|
|
10
|
+
wrapper: "w-full flex space-x-4",
|
|
11
|
+
placeholderWrapper: "flex size-12 items-center justify-center rounded-lg bg-gray-100",
|
|
12
|
+
placeholderImgIcon: "",
|
|
13
|
+
placeholderFileIcon: "",
|
|
14
|
+
placeholderIconClass: "size-7 text-gray-400",
|
|
15
|
+
textWrapper: "flex w-full items-center justify-between",
|
|
16
|
+
loadingIcon: "",
|
|
17
|
+
loadingIconClass: "text-primary size-10"
|
|
16
18
|
},
|
|
17
|
-
|
|
18
|
-
wrapper: "w-full
|
|
19
|
-
|
|
19
|
+
onPreview: {
|
|
20
|
+
wrapper: "w-full flex space-x-4",
|
|
21
|
+
previewImgWrapper: "flex size-12 items-center justify-center rounded-lg overflow-hidden bg-gray-100",
|
|
22
|
+
previewImgClass: "w-full h-full object-cover",
|
|
23
|
+
previewFileIcon: "",
|
|
24
|
+
previewFileClass: "size-7 text-gray-400",
|
|
25
|
+
textWrapper: "flex w-full items-center justify-between"
|
|
26
|
+
},
|
|
27
|
+
onFailed: {
|
|
28
|
+
wrapper: "w-full flex space-x-4",
|
|
29
|
+
failedImgWrapper: "flex size-12 items-center justify-center rounded-lg bg-gray-100",
|
|
30
|
+
failedImgIcon: "",
|
|
31
|
+
failedFileIcon: "",
|
|
32
|
+
failedIconClass: "size-7 text-gray-400",
|
|
33
|
+
textWrapper: "flex w-full items-start justify-between"
|
|
34
|
+
},
|
|
35
|
+
action: {
|
|
36
|
+
wrapper: "flex items-center space-x-4",
|
|
37
|
+
iconClass: "size-6 text-gray-400 cursor-pointer",
|
|
38
|
+
deleteIconClass: "size-6 text-danger cursor-pointer",
|
|
39
|
+
retryBtnClass: "px-0",
|
|
40
|
+
previewIcon: "i-ic:outline-remove-red-eye",
|
|
41
|
+
downloadIcon: "i-ic:outline-file-download",
|
|
42
|
+
deleteIcon: "ph:trash",
|
|
43
|
+
retryIcon: "ph:arrow-counter-clockwise"
|
|
20
44
|
},
|
|
21
45
|
background: {
|
|
22
46
|
default: "bg-white border-gray-border",
|
|
23
47
|
dragover: "bg-gray-100 border-primary"
|
|
24
48
|
},
|
|
25
|
-
button: {
|
|
26
|
-
delete: "cursor-pointer w-5 h-5 ml-2 text-gray-400 hover:text-gray-300 absolute top-6 right-6 "
|
|
27
|
-
},
|
|
28
49
|
labelIcon: "w-6 h-6 text-gray-400 text-center mb-4",
|
|
29
50
|
default: {
|
|
30
|
-
closeIcon: "i-heroicons:trash-solid",
|
|
31
51
|
filePreviewIcon: "i-heroicons:document-text-solid",
|
|
32
|
-
uploadIcon: "i-ph:cloud-arrow-up"
|
|
52
|
+
uploadIcon: "i-ph:cloud-arrow-up",
|
|
53
|
+
placeholderImgIcon: "i-material-symbols:imagesmode-outline",
|
|
54
|
+
failedImgIcon: "i-material-symbols:imagesmode-outline",
|
|
55
|
+
loadingIcon: "i-svg-spinners:180-ring-with-bg"
|
|
33
56
|
}
|
|
34
57
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare class StringHelper {
|
|
2
2
|
static genString: (length?: number) => string;
|
|
3
3
|
static withComma: (value?: number | string) => string;
|
|
4
|
+
static withFixed: (value?: number | string) => string;
|
|
4
5
|
static split: (str: string | null | undefined, separator: string | RegExp) => string[];
|
|
5
6
|
static joinURL: (...parts: string[]) => string;
|
|
6
7
|
static truncate: (str: any, num?: number) => any;
|
|
@@ -12,6 +12,12 @@ export class StringHelper {
|
|
|
12
12
|
static withComma = (value = 0) => {
|
|
13
13
|
return (+(value || 0)).toLocaleString();
|
|
14
14
|
};
|
|
15
|
+
static withFixed = (value = 0) => {
|
|
16
|
+
return (+(value || 0)).toLocaleString(void 0, {
|
|
17
|
+
minimumFractionDigits: 0,
|
|
18
|
+
maximumFractionDigits: 2
|
|
19
|
+
});
|
|
20
|
+
};
|
|
15
21
|
static split = (str, separator) => {
|
|
16
22
|
return `${str || ""}`.split(separator).filter((item) => item).map((item) => item.trim());
|
|
17
23
|
};
|