refactor/feat: 02 image & download image
This commit is contained in:
parent
251c460787
commit
78c0af9aae
4 changed files with 80 additions and 79 deletions
|
|
@ -85,15 +85,15 @@
|
||||||
|
|
||||||
"prefix": [
|
"prefix": [
|
||||||
{
|
{
|
||||||
"label": "Mr.",
|
"label": "Mr",
|
||||||
"value": "mr"
|
"value": "mr"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Mrs.",
|
"label": "Mrs",
|
||||||
"value": "mrs"
|
"value": "mrs"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Miss.",
|
"label": "Miss",
|
||||||
"value": "miss"
|
"value": "miss"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import AppBox from './app/AppBox.vue';
|
import AppBox from './app/AppBox.vue';
|
||||||
|
import { CancelButton, SaveButton } from './button';
|
||||||
|
|
||||||
defineExpose({ browse });
|
defineExpose({ browse });
|
||||||
defineProps<{
|
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>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<q-dialog v-model="dialogState">
|
<q-dialog v-model="dialogState">
|
||||||
|
|
@ -90,12 +107,22 @@ function change(e: Event) {
|
||||||
<div style="position: fixed; padding: var(--size-2)">
|
<div style="position: fixed; padding: var(--size-2)">
|
||||||
<q-btn
|
<q-btn
|
||||||
class="upload-image-btn"
|
class="upload-image-btn"
|
||||||
icon="mdi-camera"
|
icon="mdi-camera-outline"
|
||||||
size="md"
|
size="md"
|
||||||
unelevated
|
unelevated
|
||||||
round
|
round
|
||||||
v-if="!changeDisabled"
|
v-if="!changeDisabled"
|
||||||
@click="inputFile?.click()"
|
@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>
|
></q-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -106,6 +133,7 @@ function change(e: Event) {
|
||||||
<q-btn
|
<q-btn
|
||||||
dense
|
dense
|
||||||
unelevated
|
unelevated
|
||||||
|
flat
|
||||||
:color="$q.dark.isActive ? 'grey-9' : 'grey-4'"
|
:color="$q.dark.isActive ? 'grey-9' : 'grey-4'"
|
||||||
:text-color="$q.dark.isActive ? 'grey-1' : 'grey-10'"
|
:text-color="$q.dark.isActive ? 'grey-1' : 'grey-10'"
|
||||||
:label="$t('clear')"
|
:label="$t('clear')"
|
||||||
|
|
@ -123,29 +151,19 @@ function change(e: Event) {
|
||||||
"
|
"
|
||||||
v-if="clearButton"
|
v-if="clearButton"
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<CancelButton
|
||||||
dense
|
outlined
|
||||||
unelevated
|
class="q-px-md q-mr-sm"
|
||||||
:color="$q.dark.isActive ? 'grey-9' : 'grey-4'"
|
|
||||||
:text-color="$q.dark.isActive ? 'grey-1' : 'grey-10'"
|
|
||||||
:label="$t('cancel')"
|
|
||||||
@click="
|
@click="
|
||||||
inputFile && (inputFile.value = ''),
|
inputFile && (inputFile.value = ''),
|
||||||
(imageUrl = defaultUrl || fallbackUrl || ''),
|
(imageUrl = defaultUrl || fallbackUrl || ''),
|
||||||
(file = null)
|
(file = null)
|
||||||
"
|
"
|
||||||
class="q-px-md q-mr-sm"
|
|
||||||
v-close-popup
|
v-close-popup
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<SaveButton
|
||||||
dense
|
outlined
|
||||||
unelevated
|
|
||||||
id="submit-btn"
|
|
||||||
type="submit"
|
|
||||||
color="primary"
|
|
||||||
class="q-px-md"
|
|
||||||
@click="$emit('save', inputFile?.files?.[0] || null, imageUrl)"
|
@click="$emit('save', inputFile?.files?.[0] || null, imageUrl)"
|
||||||
:label="$t('save')"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</AppBox>
|
</AppBox>
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,6 @@ const showOverlay = ref(false);
|
||||||
class="relative-position"
|
class="relative-position"
|
||||||
style="z-index: 1"
|
style="z-index: 1"
|
||||||
:style="{
|
:style="{
|
||||||
background: `${bgColor || 'var(--brand-1)'}`,
|
|
||||||
color: `${color || 'white'}`,
|
color: `${color || 'white'}`,
|
||||||
cursor: `${noImageAction ? 'default' : 'pointer'}`,
|
cursor: `${noImageAction ? 'default' : 'pointer'}`,
|
||||||
}"
|
}"
|
||||||
|
|
@ -93,8 +92,8 @@ const showOverlay = ref(false);
|
||||||
<template #error>
|
<template #error>
|
||||||
<div
|
<div
|
||||||
class="full-width full-height flex items-center justify-center"
|
class="full-width full-height flex items-center justify-center"
|
||||||
style="background-color: transparent"
|
|
||||||
:style="{
|
:style="{
|
||||||
|
background: `${bgColor || 'var(--brand-1)'}`,
|
||||||
color: `${color || 'white'}`,
|
color: `${color || 'white'}`,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
|
|
@ -105,8 +104,8 @@ const showOverlay = ref(false);
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="full-width full-height flex items-center justify-center"
|
class="full-width full-height flex items-center justify-center"
|
||||||
style="background-color: transparent"
|
|
||||||
:style="{
|
:style="{
|
||||||
|
background: `${bgColor || 'var(--brand-1)'}`,
|
||||||
color: `${color || 'white'}`,
|
color: `${color || 'white'}`,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
|
|
@ -114,7 +113,16 @@ const showOverlay = ref(false);
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</q-img>
|
</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
|
<q-badge
|
||||||
v-if="!hideActive"
|
v-if="!hideActive"
|
||||||
class="absolute-bottom-right"
|
class="absolute-bottom-right"
|
||||||
|
|
|
||||||
|
|
@ -237,33 +237,6 @@ const imageUrl = ref<string>('');
|
||||||
const profileFileImg = ref<File | null>(null);
|
const profileFileImg = ref<File | null>(null);
|
||||||
const imageDialog = ref(false);
|
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');
|
// const inputFile = document.createElement('input');
|
||||||
// inputFile.type = 'file';
|
// inputFile.type = 'file';
|
||||||
// inputFile.accept = 'image/*';
|
// inputFile.accept = 'image/*';
|
||||||
|
|
@ -317,23 +290,18 @@ const columns = [
|
||||||
},
|
},
|
||||||
] satisfies QTableProps['columns'];
|
] satisfies QTableProps['columns'];
|
||||||
|
|
||||||
reader.addEventListener('load', () => {
|
// reader.addEventListener('load', () => {
|
||||||
if (typeof reader.result === 'string') {
|
// if (typeof reader.result === 'string') {
|
||||||
urlProfile.value = reader.result;
|
// urlProfile.value = reader.result;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (infoDrawerEdit.value) infoPersonCard.value[0].img = urlProfile.value;
|
// if (infoDrawerEdit.value) infoPersonCard.value[0].img = urlProfile.value;
|
||||||
});
|
// });
|
||||||
|
|
||||||
watch(profileFileImg, () => {
|
watch(profileFileImg, () => {
|
||||||
if (profileFileImg.value) reader.readAsDataURL(profileFileImg.value);
|
if (profileFileImg.value) reader.readAsDataURL(profileFileImg.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
inputFileImg.addEventListener('change', (e) => {
|
|
||||||
profileFileImg.value =
|
|
||||||
(e.currentTarget as HTMLInputElement).files?.[0] || null;
|
|
||||||
});
|
|
||||||
|
|
||||||
const selectorList = computed(() => [
|
const selectorList = computed(() => [
|
||||||
{ label: 'USER', count: typeStats.value?.USER || 0 },
|
{ label: 'USER', count: typeStats.value?.USER || 0 },
|
||||||
{ label: 'MESSENGER', count: typeStats.value?.MESSENGER || 0 },
|
{ label: 'MESSENGER', count: typeStats.value?.MESSENGER || 0 },
|
||||||
|
|
@ -427,7 +395,7 @@ function onClose() {
|
||||||
brId.value = '';
|
brId.value = '';
|
||||||
userId.value = '';
|
userId.value = '';
|
||||||
userCode.value = '';
|
userCode.value = '';
|
||||||
urlProfile.value = undefined;
|
urlProfile.value = '';
|
||||||
profileFileImg.value = null;
|
profileFileImg.value = null;
|
||||||
infoDrawerEdit.value = false;
|
infoDrawerEdit.value = false;
|
||||||
agencyFile.value = [];
|
agencyFile.value = [];
|
||||||
|
|
@ -441,7 +409,6 @@ function onClose() {
|
||||||
mapUserType(selectorLabel.value);
|
mapUserType(selectorLabel.value);
|
||||||
flowStore.rotate();
|
flowStore.rotate();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
if (profileSubmit.value) {
|
if (profileSubmit.value) {
|
||||||
formData.value.profileImage = profileFileImg.value as File;
|
formData.value.profileImage = profileFileImg.value as File;
|
||||||
|
|
@ -1171,7 +1138,7 @@ watch(
|
||||||
<q-img
|
<q-img
|
||||||
class="text-center"
|
class="text-center"
|
||||||
:ratio="1"
|
:ratio="1"
|
||||||
:src="`${apiBaseUrl}/user/${props.row.id}/image`"
|
:src="`${apiBaseUrl}/user/${props.row.id}/image?ts=${Date.now()}`"
|
||||||
>
|
>
|
||||||
<template #error>
|
<template #error>
|
||||||
<div
|
<div
|
||||||
|
|
@ -1650,7 +1617,7 @@ watch(
|
||||||
:menu="formMenuIcon"
|
:menu="formMenuIcon"
|
||||||
:readonly="!infoDrawerEdit"
|
:readonly="!infoDrawerEdit"
|
||||||
:toggleTitle="$t('formDialogTitleUserStatus')"
|
:toggleTitle="$t('formDialogTitleUserStatus')"
|
||||||
:title="`${formData.firstName} ${formData.lastName}`"
|
:title="`${$i18n.locale === 'en-US' ? `${formData.firstNameEN} ${formData.lastNameEN}` : `${formData.firstName} ${formData.lastName}`}`"
|
||||||
:caption="userCode"
|
:caption="userCode"
|
||||||
:img="
|
:img="
|
||||||
urlProfile ||
|
urlProfile ||
|
||||||
|
|
@ -1659,8 +1626,14 @@ watch(
|
||||||
female: '/no-img-female.png',
|
female: '/no-img-female.png',
|
||||||
}[formData.gender]
|
}[formData.gender]
|
||||||
"
|
"
|
||||||
|
:fallbackImg="
|
||||||
|
{
|
||||||
|
male: '/no-img-man.png',
|
||||||
|
female: '/no-img-female.png',
|
||||||
|
}[formData.gender]
|
||||||
|
"
|
||||||
@view="openImageDialog"
|
@view="openImageDialog"
|
||||||
@edit="inputFileImg.click()"
|
@edit="refImageUpload && refImageUpload.browse()"
|
||||||
@update:toggle-status="
|
@update:toggle-status="
|
||||||
async (v) => {
|
async (v) => {
|
||||||
await triggerChangeStatus(infoPersonId, 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%)"
|
bgColor="linear-gradient(135deg, rgba(43,137,223,1) 0%, rgba(230,51,81,1) 100%)"
|
||||||
v-model:toggle-status="formData.status"
|
v-model:toggle-status="formData.status"
|
||||||
:menu="formMenuIcon"
|
:menu="formMenuIcon"
|
||||||
:img="urlProfile || undefined"
|
:img="
|
||||||
|
urlProfile ||
|
||||||
|
{
|
||||||
|
male: '/no-img-man.png',
|
||||||
|
female: '/no-img-female.png',
|
||||||
|
}[formData.gender]
|
||||||
|
"
|
||||||
:toggleTitle="$t('formDialogTitleUserStatus')"
|
: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
|
hideFade
|
||||||
@view="imageDialog = true"
|
@view="imageDialog = true"
|
||||||
@edit="refImageUpload && refImageUpload.browse()"
|
@edit="refImageUpload && refImageUpload.browse()"
|
||||||
|
|
@ -1885,16 +1870,6 @@ watch(
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</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
|
<div
|
||||||
class="col surface-1 q-ma-lg rounded bordered row relative-position"
|
class="col surface-1 q-ma-lg rounded bordered row relative-position"
|
||||||
|
|
@ -2015,12 +1990,12 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
</DialogForm>
|
</DialogForm>
|
||||||
|
|
||||||
|
<!-- :default-url="`${baseUrl}/user/${currentUser?.id}/image`" -->
|
||||||
<ImageUploadDialog
|
<ImageUploadDialog
|
||||||
ref="refImageUpload"
|
ref="refImageUpload"
|
||||||
v-model:dialogState="imageDialog"
|
v-model:dialogState="imageDialog"
|
||||||
v-model:file="profileFileImg"
|
v-model:file="profileFileImg"
|
||||||
v-model:image-url="urlProfile"
|
v-model:image-url="urlProfile"
|
||||||
:default-url="`${baseUrl}/user/${currentUser?.id}/image`"
|
|
||||||
:hiddenFooter="!isImageEdit"
|
:hiddenFooter="!isImageEdit"
|
||||||
:changeDisabled="!isImageEdit"
|
:changeDisabled="!isImageEdit"
|
||||||
@save="imageDialog = false"
|
@save="imageDialog = false"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue