refactor/feat: 02 image & download image

This commit is contained in:
puriphatt 2024-08-22 13:48:59 +07:00
parent 251c460787
commit 78c0af9aae
4 changed files with 80 additions and 79 deletions

View file

@ -85,15 +85,15 @@
"prefix": [
{
"label": "Mr.",
"label": "Mr",
"value": "mr"
},
{
"label": "Mrs.",
"label": "Mrs",
"value": "mrs"
},
{
"label": "Miss.",
"label": "Miss",
"value": "miss"
}
],

View file

@ -1,5 +1,6 @@
<script lang="ts" setup>
import AppBox from './app/AppBox.vue';
import { CancelButton, SaveButton } from './button';
defineExpose({ browse });
defineProps<{
@ -58,6 +59,22 @@ function change(e: Event) {
}
}
}
async function downloadImage(url: string) {
const res = await fetch(url);
const blob = await res.blob();
let extension = '';
if (blob.type === 'image/jpeg') extension = '.jpg';
if (blob.type === 'image/png') extension = '.png';
let a = document.createElement('a');
a.download = `download${extension}`;
a.href = window.URL.createObjectURL(blob);
a.click();
a.remove();
}
</script>
<template>
<q-dialog v-model="dialogState">
@ -90,12 +107,22 @@ function change(e: Event) {
<div style="position: fixed; padding: var(--size-2)">
<q-btn
class="upload-image-btn"
icon="mdi-camera"
icon="mdi-camera-outline"
size="md"
unelevated
round
v-if="!changeDisabled"
@click="inputFile?.click()"
style="color: hsla(var(--stone-0-hsl) / 0.7)"
></q-btn>
<q-btn
class="upload-image-btn q-ml-md"
icon="mdi-download-outline"
size="md"
unelevated
round
@click="downloadImage(imageUrl)"
style="color: hsla(var(--stone-0-hsl) / 0.7)"
></q-btn>
</div>
</div>
@ -106,6 +133,7 @@ function change(e: Event) {
<q-btn
dense
unelevated
flat
:color="$q.dark.isActive ? 'grey-9' : 'grey-4'"
:text-color="$q.dark.isActive ? 'grey-1' : 'grey-10'"
:label="$t('clear')"
@ -123,29 +151,19 @@ function change(e: Event) {
"
v-if="clearButton"
/>
<q-btn
dense
unelevated
:color="$q.dark.isActive ? 'grey-9' : 'grey-4'"
:text-color="$q.dark.isActive ? 'grey-1' : 'grey-10'"
:label="$t('cancel')"
<CancelButton
outlined
class="q-px-md q-mr-sm"
@click="
inputFile && (inputFile.value = ''),
(imageUrl = defaultUrl || fallbackUrl || ''),
(file = null)
"
class="q-px-md q-mr-sm"
v-close-popup
/>
<q-btn
dense
unelevated
id="submit-btn"
type="submit"
color="primary"
class="q-px-md"
<SaveButton
outlined
@click="$emit('save', inputFile?.files?.[0] || null, imageUrl)"
:label="$t('save')"
/>
</div>
</AppBox>

View file

@ -74,7 +74,6 @@ const showOverlay = ref(false);
class="relative-position"
style="z-index: 1"
:style="{
background: `${bgColor || 'var(--brand-1)'}`,
color: `${color || 'white'}`,
cursor: `${noImageAction ? 'default' : 'pointer'}`,
}"
@ -93,8 +92,8 @@ const showOverlay = ref(false);
<template #error>
<div
class="full-width full-height flex items-center justify-center"
style="background-color: transparent"
:style="{
background: `${bgColor || 'var(--brand-1)'}`,
color: `${color || 'white'}`,
}"
>
@ -105,8 +104,8 @@ const showOverlay = ref(false);
<div
v-else
class="full-width full-height flex items-center justify-center"
style="background-color: transparent"
:style="{
background: `${bgColor || 'var(--brand-1)'}`,
color: `${color || 'white'}`,
}"
>
@ -114,7 +113,16 @@ const showOverlay = ref(false);
</div>
</template>
</q-img>
<q-icon id="profile-view" v-else :name="icon || 'mdi-account'" />
<div
v-else
class="full-width full-height flex items-center justify-center"
:style="{
background: `${bgColor || 'var(--brand-1)'}`,
color: `${color || 'white'}`,
}"
>
<q-icon :name="icon || 'mdi-account'" />
</div>
<q-badge
v-if="!hideActive"
class="absolute-bottom-right"

View file

@ -237,33 +237,6 @@ const imageUrl = ref<string>('');
const profileFileImg = ref<File | null>(null);
const imageDialog = ref(false);
const inputFileImg = (() => {
const element = document.createElement('input');
element.type = 'file';
element.accept = 'image/*';
const reader = new FileReader();
reader.addEventListener('load', () => {
if (typeof reader.result === 'string') imageUrl.value = reader.result;
if (infoDrawerEdit.value && currentUser.value)
currentUser.value.profileImageUrl = imageUrl.value as string;
// profileUrl.value = currentUser.value?.profileImageUrl as string;
// if (infoDrawerEmployeeEdit.value && infoEmployeePersonCard.value)
// infoEmployeePersonCard.value[0].img = profileUrl.value as string;
});
element.addEventListener('change', () => {
profileFileImg.value = element.files?.[0] || null;
if (profileFileImg.value) {
reader.readAsDataURL(profileFileImg.value);
}
});
return element;
})();
// const inputFile = document.createElement('input');
// inputFile.type = 'file';
// inputFile.accept = 'image/*';
@ -317,23 +290,18 @@ const columns = [
},
] satisfies QTableProps['columns'];
reader.addEventListener('load', () => {
if (typeof reader.result === 'string') {
urlProfile.value = reader.result;
}
// reader.addEventListener('load', () => {
// if (typeof reader.result === 'string') {
// urlProfile.value = reader.result;
// }
if (infoDrawerEdit.value) infoPersonCard.value[0].img = urlProfile.value;
});
// if (infoDrawerEdit.value) infoPersonCard.value[0].img = urlProfile.value;
// });
watch(profileFileImg, () => {
if (profileFileImg.value) reader.readAsDataURL(profileFileImg.value);
});
inputFileImg.addEventListener('change', (e) => {
profileFileImg.value =
(e.currentTarget as HTMLInputElement).files?.[0] || null;
});
const selectorList = computed(() => [
{ label: 'USER', count: typeStats.value?.USER || 0 },
{ label: 'MESSENGER', count: typeStats.value?.MESSENGER || 0 },
@ -427,7 +395,7 @@ function onClose() {
brId.value = '';
userId.value = '';
userCode.value = '';
urlProfile.value = undefined;
urlProfile.value = '';
profileFileImg.value = null;
infoDrawerEdit.value = false;
agencyFile.value = [];
@ -441,7 +409,6 @@ function onClose() {
mapUserType(selectorLabel.value);
flowStore.rotate();
}
async function onSubmit() {
if (profileSubmit.value) {
formData.value.profileImage = profileFileImg.value as File;
@ -1171,7 +1138,7 @@ watch(
<q-img
class="text-center"
:ratio="1"
:src="`${apiBaseUrl}/user/${props.row.id}/image`"
:src="`${apiBaseUrl}/user/${props.row.id}/image?ts=${Date.now()}`"
>
<template #error>
<div
@ -1650,7 +1617,7 @@ watch(
:menu="formMenuIcon"
:readonly="!infoDrawerEdit"
:toggleTitle="$t('formDialogTitleUserStatus')"
:title="`${formData.firstName} ${formData.lastName}`"
:title="`${$i18n.locale === 'en-US' ? `${formData.firstNameEN} ${formData.lastNameEN}` : `${formData.firstName} ${formData.lastName}`}`"
:caption="userCode"
:img="
urlProfile ||
@ -1659,8 +1626,14 @@ watch(
female: '/no-img-female.png',
}[formData.gender]
"
:fallbackImg="
{
male: '/no-img-man.png',
female: '/no-img-female.png',
}[formData.gender]
"
@view="openImageDialog"
@edit="inputFileImg.click()"
@edit="refImageUpload && refImageUpload.browse()"
@update:toggle-status="
async (v) => {
await triggerChangeStatus(infoPersonId, v);
@ -1871,9 +1844,21 @@ watch(
bgColor="linear-gradient(135deg, rgba(43,137,223,1) 0%, rgba(230,51,81,1) 100%)"
v-model:toggle-status="formData.status"
:menu="formMenuIcon"
:img="urlProfile || undefined"
:img="
urlProfile ||
{
male: '/no-img-man.png',
female: '/no-img-female.png',
}[formData.gender]
"
:toggleTitle="$t('formDialogTitleUserStatus')"
:title="`${formData.firstName} ${formData.lastName}`"
:title="`${$i18n.locale === 'en-US' ? `${formData.firstNameEN} ${formData.lastNameEN}` : `${formData.firstName} ${formData.lastName}`}`"
:fallbackImg="
{
male: '/no-img-man.png',
female: '/no-img-female.png',
}[formData.gender]
"
hideFade
@view="imageDialog = true"
@edit="refImageUpload && refImageUpload.browse()"
@ -1885,16 +1870,6 @@ watch(
"
/>
</div>
<!-- <template #prepend>
<ProfileUpload
prefix-id="form-dialog-personnel"
v-model:url-profile="urlProfile"
v-model:status-toggle="statusToggle"
v-model:profile-submit="profileSubmit"
@input-file="inputFileImg.click()"
@cancel-file="inputFileImg.value = ''"
/>
</template> -->
<div
class="col surface-1 q-ma-lg rounded bordered row relative-position"
@ -2015,12 +1990,12 @@ watch(
</div>
</DialogForm>
<!-- :default-url="`${baseUrl}/user/${currentUser?.id}/image`" -->
<ImageUploadDialog
ref="refImageUpload"
v-model:dialogState="imageDialog"
v-model:file="profileFileImg"
v-model:image-url="urlProfile"
:default-url="`${baseUrl}/user/${currentUser?.id}/image`"
:hiddenFooter="!isImageEdit"
:changeDisabled="!isImageEdit"
@save="imageDialog = false"