@ramathibodi/nuxt-commons 0.1.26 → 0.1.27
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/dist/module.json
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import {
|
|
2
|
+
import {type Ref, ref, watch} from 'vue'
|
|
3
3
|
import {useAlert} from '../../../composables/alert'
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
readonly?: boolean;
|
|
8
|
-
label?: string;
|
|
9
|
-
}
|
|
4
|
+
import {isEqual} from 'lodash-es'
|
|
5
|
+
import type {FormDialogCallback} from "../../../types/formDialog";
|
|
6
|
+
|
|
10
7
|
|
|
11
|
-
const props = defineProps<Props>();
|
|
12
8
|
const emit = defineEmits<{
|
|
13
9
|
(e: "update:modelValue", value: {}): void;
|
|
14
10
|
}>();
|
|
@@ -21,58 +17,55 @@ interface Image {
|
|
|
21
17
|
props: {};
|
|
22
18
|
}
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
interface Props {
|
|
21
|
+
modelValue?: any[];
|
|
22
|
+
readonly?: boolean;
|
|
23
|
+
label?: string;
|
|
24
|
+
}
|
|
25
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
26
|
+
modelValue: () => [] as any[],
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const images = ref<any[]>([]);
|
|
30
|
+
// uploadImages = images that are imported by FileBtn
|
|
31
|
+
const uploadImages: Ref<any[]> = ref([]);
|
|
32
|
+
// dialog = dialog for capturing image
|
|
25
33
|
const dialog: Ref<boolean> = ref(false);
|
|
34
|
+
// dialogUpdate, dataUpdate = dialog for editing image
|
|
26
35
|
const dialogUpdate: Ref<boolean> = ref(false);
|
|
27
36
|
const dataUpdate: Ref<Image> = ref({
|
|
28
37
|
title: "",
|
|
29
38
|
data: "",
|
|
30
39
|
props: {},
|
|
31
40
|
});
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
// remove selected image
|
|
32
44
|
const remove = (index: number) => {
|
|
33
45
|
images.value.splice(index, 1);
|
|
34
46
|
};
|
|
35
47
|
|
|
48
|
+
// open dialog for editing selected image
|
|
36
49
|
const setDataUpdate = (data: Image) => {
|
|
37
50
|
dataUpdate.value = data;
|
|
38
51
|
dialogUpdate.value = true;
|
|
39
52
|
};
|
|
40
53
|
|
|
41
54
|
|
|
42
|
-
interface FileBase64 {
|
|
43
|
-
base64string: string;
|
|
44
|
-
mineType: string;
|
|
45
|
-
filename: string;
|
|
46
|
-
}
|
|
47
55
|
|
|
48
|
-
|
|
49
|
-
const uploadImages: Ref<any[]> = ref([]);
|
|
56
|
+
// check if File name is already exist
|
|
50
57
|
const checkDuplicationName = async (currentImageName: string) => {
|
|
51
58
|
for (const {title} of images.value) {
|
|
52
|
-
if(isEqual(title, currentImageName)) return true
|
|
59
|
+
if (isEqual(title, currentImageName)) return true
|
|
53
60
|
}
|
|
54
61
|
}
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
if(await checkDuplicationName(image.name)){
|
|
60
|
-
duplicatedFileName.value += `${image.name},`
|
|
61
|
-
}else{
|
|
62
|
-
const fileBase64: any = await convertFileToBase64(image);
|
|
63
|
-
if (isImage(fileBase64)) {
|
|
64
|
-
addImage(fileBase64);
|
|
65
|
-
} else {
|
|
66
|
-
alert?.addAlert({message: `ไฟล์ "${fileBase64.filename}" ไม่ใช่ไฟล์นามสกุล .jpg หรือ .jpeg`, alertType: 'error'})
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
uploadImages.value = []
|
|
71
|
-
if(duplicatedFileName.value !== ""){
|
|
72
|
-
alert?.addAlert({message: `ไม่สามารถอัพโหลดไฟล์ ${duplicatedFileName.value}`, alertType: 'error'})
|
|
73
|
-
duplicatedFileName.value = ""
|
|
74
|
-
}
|
|
62
|
+
// check if the base64 is image or not
|
|
63
|
+
const isImage = (fileBase64: any) => {
|
|
64
|
+
const typeFile: string = fileBase64.mineType.substring(5, 10);
|
|
65
|
+
return typeFile === "image";
|
|
75
66
|
};
|
|
67
|
+
|
|
68
|
+
// convert FIle that is uploaded by FileBtn to base64
|
|
76
69
|
const convertFileToBase64 = async (file: any) => {
|
|
77
70
|
try {
|
|
78
71
|
const readPromise: any = new Promise((resolve, reject) => {
|
|
@@ -97,22 +90,92 @@ const convertFileToBase64 = async (file: any) => {
|
|
|
97
90
|
alert?.addAlert({message: error, alertType: 'error'})
|
|
98
91
|
}
|
|
99
92
|
};
|
|
100
|
-
const isImage = (fileBase64: any) => {
|
|
101
|
-
const typeFile: string = fileBase64.mineType.substring(5, 10);
|
|
102
|
-
return typeFile === "image" ? true : false;
|
|
103
|
-
};
|
|
104
93
|
|
|
105
|
-
|
|
94
|
+
// push image into Field
|
|
95
|
+
const addImage = (data: Image) => {
|
|
106
96
|
images.value.push({
|
|
107
|
-
title: data.
|
|
108
|
-
data:
|
|
97
|
+
title: data.title,
|
|
98
|
+
data: data.data,
|
|
109
99
|
props: {},
|
|
110
100
|
});
|
|
111
101
|
dialog.value = false;
|
|
112
102
|
};
|
|
103
|
+
|
|
104
|
+
const update = async () => {
|
|
105
|
+
const duplicatedFileName = ref("")
|
|
106
|
+
for (const image of uploadImages.value) {
|
|
107
|
+
if (await checkDuplicationName(image.name)) {
|
|
108
|
+
duplicatedFileName.value += `${image.name},`
|
|
109
|
+
} else {
|
|
110
|
+
const fileBase64: any = await convertFileToBase64(image);
|
|
111
|
+
if (isImage(fileBase64)) {
|
|
112
|
+
addImage({
|
|
113
|
+
title: fileBase64.filename,
|
|
114
|
+
data: `${fileBase64.mineType},${fileBase64.base64string}`,
|
|
115
|
+
props: {},
|
|
116
|
+
})
|
|
117
|
+
} else {
|
|
118
|
+
alert?.addAlert({
|
|
119
|
+
message: `ไฟล์ "${fileBase64.filename}" ไม่ใช่ไฟล์นามสกุล .jpg หรือ .jpeg`,
|
|
120
|
+
alertType: 'error'
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
uploadImages.value = []
|
|
126
|
+
if (duplicatedFileName.value !== "") {
|
|
127
|
+
alert?.addAlert({message: `ไม่สามารถอัพโหลดไฟล์ ${duplicatedFileName.value}`, alertType: 'error'})
|
|
128
|
+
duplicatedFileName.value = ""
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// Capture Image
|
|
133
|
+
const modelData = ref();
|
|
134
|
+
const captureImage = (image: any, callback: FormDialogCallback) => {
|
|
135
|
+
addImage({
|
|
136
|
+
title: Math.random().toString(36).slice(2, 11),
|
|
137
|
+
data: image.imageCapture,
|
|
138
|
+
props: {}
|
|
139
|
+
})
|
|
140
|
+
callback.done()
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// open Fullscreen image
|
|
144
|
+
const dialogImageFullScreen = ref(false)
|
|
145
|
+
const imageFullScreen = ref({
|
|
146
|
+
title: "",
|
|
147
|
+
image: ""
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
const openImageFullScreen = (image: { [key: string]: string }) => {
|
|
151
|
+
dialogImageFullScreen.value = true
|
|
152
|
+
imageFullScreen.value.title = image.title
|
|
153
|
+
imageFullScreen.value.image = image.data
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
113
157
|
watch(images, () => {
|
|
114
|
-
emit("update:modelValue", images);
|
|
115
|
-
}, {
|
|
158
|
+
emit("update:modelValue", images.value);
|
|
159
|
+
}, {deep: true});
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
// updating when the parent component adds image to v-model
|
|
163
|
+
watch(props.modelValue, () => {
|
|
164
|
+
images.value = props.modelValue
|
|
165
|
+
}, {deep: true});
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
onMounted(() => {
|
|
169
|
+
// import images by v-model
|
|
170
|
+
for (const modelValue of props.modelValue) {
|
|
171
|
+
addImage({
|
|
172
|
+
title: modelValue.title ?? Math.random().toString(36).slice(2, 11),
|
|
173
|
+
data: modelValue.data,
|
|
174
|
+
props: {}
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
|
|
116
179
|
</script>
|
|
117
180
|
|
|
118
181
|
<template>
|
|
@@ -140,7 +203,7 @@ watch(images, () => {
|
|
|
140
203
|
<VCardText>
|
|
141
204
|
<VRow dense justify="center">
|
|
142
205
|
<VCol v-for="(image, index) in images" :key="index" cols="4">
|
|
143
|
-
<VCard
|
|
206
|
+
<VCard>
|
|
144
207
|
<VToolbar density="compact">
|
|
145
208
|
<VToolbarTitle>
|
|
146
209
|
{{ image.title }}
|
|
@@ -161,13 +224,16 @@ watch(images, () => {
|
|
|
161
224
|
</VToolbar>
|
|
162
225
|
<v-img
|
|
163
226
|
:src="image.data"
|
|
164
|
-
@click="setDataUpdate(image)"
|
|
165
|
-
|
|
227
|
+
@click="readonly ? openImageFullScreen(image) : setDataUpdate(image)"
|
|
228
|
+
height="250"
|
|
229
|
+
/>
|
|
166
230
|
</VCard>
|
|
167
231
|
</VCol>
|
|
168
232
|
</VRow>
|
|
169
233
|
</VCardText>
|
|
170
234
|
</VCard>
|
|
235
|
+
|
|
236
|
+
|
|
171
237
|
<VDialog
|
|
172
238
|
v-model="dialogUpdate"
|
|
173
239
|
fullscreen
|
|
@@ -178,10 +244,21 @@ watch(images, () => {
|
|
|
178
244
|
@closedDialog="dialogUpdate = false"
|
|
179
245
|
></FormImagesPad>
|
|
180
246
|
</VDialog>
|
|
181
|
-
<VDialog v-model="dialog">
|
|
182
|
-
<FormImagesCapture
|
|
183
247
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
248
|
+
<FormDialog v-model="dialog" :form-data="modelData" @create="captureImage">
|
|
249
|
+
<template #default="{ data }">
|
|
250
|
+
<FormImagesCapture v-model="data.imageCapture"/>
|
|
251
|
+
</template>
|
|
252
|
+
</FormDialog>
|
|
253
|
+
|
|
254
|
+
<v-dialog v-model="dialogImageFullScreen">
|
|
255
|
+
<v-toolbar :title="imageFullScreen.title">
|
|
256
|
+
<v-spacer/>
|
|
257
|
+
<v-btn icon="mdi mdi-close" @click="dialogImageFullScreen = false"/>
|
|
258
|
+
</v-toolbar>
|
|
259
|
+
<v-card height="80vh">
|
|
260
|
+
<v-img :src="imageFullScreen.image"/>
|
|
261
|
+
</v-card>
|
|
262
|
+
|
|
263
|
+
</v-dialog>
|
|
187
264
|
</template>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import {VAutocomplete} from 'vuetify/components/VAutocomplete'
|
|
3
3
|
import {concat, isEmpty, sortBy} from 'lodash-es'
|
|
4
|
-
import {computed, ref, watch} from 'vue'
|
|
4
|
+
import {computed, ref, watch,watchEffect} from 'vue'
|
|
5
5
|
import {watchDebounced} from '@vueuse/core'
|
|
6
6
|
import {useFuzzy} from '../../composables/utils/fuzzy'
|
|
7
7
|
import {useGraphQl} from '../../composables/graphql'
|
|
@@ -66,16 +66,15 @@ function query(groupKey: string, filterText: string | undefined) {
|
|
|
66
66
|
})
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
if (
|
|
69
|
+
watchEffect(()=>{
|
|
70
|
+
if (props.waitForFilter && !props.filterText) {
|
|
71
71
|
masterItems.value = []
|
|
72
72
|
items.value = []
|
|
73
73
|
selectedItem.value = undefined
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
74
|
+
} else {
|
|
76
75
|
query(props.groupKey, props.filterText)
|
|
77
76
|
}
|
|
78
|
-
}
|
|
77
|
+
})
|
|
79
78
|
|
|
80
79
|
watch(() => props.modelValue, (newValue) => {
|
|
81
80
|
selectedItem.value = newValue
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ramathibodi/nuxt-commons",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.27",
|
|
4
4
|
"description": "Ramathibodi Nuxt modules for common components",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -114,5 +114,5 @@
|
|
|
114
114
|
"vitest": "^1.6.0",
|
|
115
115
|
"vue-tsc": "2.0.29"
|
|
116
116
|
},
|
|
117
|
-
"packageManager": "pnpm@9.12.
|
|
117
|
+
"packageManager": "pnpm@9.12.1+sha512.e5a7e52a4183a02d5931057f7a0dbff9d5e9ce3161e33fa68ae392125b79282a8a8a470a51dfc8a0ed86221442eb2fb57019b0990ed24fab519bf0e1bc5ccfc4"
|
|
118
118
|
}
|