feat: agencies => image upload (#67)

This commit is contained in:
puriphatt 2024-11-08 17:21:25 +07:00 committed by GitHub
parent 86a3247732
commit 4e622153ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 346 additions and 50 deletions

View file

@ -1,39 +1,70 @@
<script setup lang="ts">
import DialogForm from 'src/components/DialogForm.vue';
import { reactive, ref, watch } from 'vue';
import { InstitutionPayload } from 'src/stores/institution/types';
import { Icon } from '@iconify/vue/dist/iconify.js';
import { useInstitution } from 'src/stores/institution';
import { baseUrl } from 'src/stores/utils';
import DrawerInfo from 'src/components/DrawerInfo.vue';
import DialogForm from 'src/components/DialogForm.vue';
import ProfileBanner from 'src/components/ProfileBanner.vue';
import SideMenu from 'src/components/SideMenu.vue';
import FormBasicInfoAgencies from 'src/components/07_agencies-management/FormBasicInfoAgencies.vue';
import AddressForm from 'src/components/form/AddressForm.vue';
import {
UndoButton,
SaveButton,
EditButton,
DeleteButton,
} from 'src/components/button';
import { InstitutionPayload } from 'src/stores/institution/types';
import AddressForm from 'src/components/form/AddressForm.vue';
import ImageUploadDialog from 'src/components/ImageUploadDialog.vue';
const institutionStore = useInstitution();
const model = defineModel<boolean>({ required: true, default: false });
const drawerModel = defineModel<boolean>('drawerModel', {
required: true,
default: false,
});
const onCreateImageList = defineModel<{
selectedImage: string;
list: { url: string; imgFile: File | null; name: string }[];
}>('onCreateImageList', { default: { selectedImage: '', list: [] } });
withDefaults(
const imageState = reactive({
imageDialog: false,
isImageEdit: false,
refreshImageState: false,
imageUrl: '',
});
const imageFile = ref<File | null>(null);
const imageList = ref<{ selectedImage: string; list: string[] }>();
const props = withDefaults(
defineProps<{
readonly?: boolean;
isEdit?: boolean;
dataId?: string;
}>(),
{ readonly: false, isEdit: false },
{ readonly: false, isEdit: false, dataId: '' },
);
defineEmits<{
defineExpose({ clearImageState });
const emit = defineEmits<{
(e: 'submit'): void;
(e: 'close'): void;
(e: 'changeStatus'): void;
(e: 'drawerUndo'): void;
(e: 'drawerEdit'): void;
(e: 'drawerDelete'): void;
(e: 'addImage'): void;
(e: 'removeImage'): void;
(e: 'submitImage', name: string): void;
}>();
const data = defineModel<InstitutionPayload>('data', {
@ -54,8 +85,96 @@ const data = defineModel<InstitutionPayload>('data', {
subDistrictId: '',
districtId: '',
provinceId: '',
selectedImage: '',
},
});
function viewImage() {
imageState.imageDialog = true;
imageState.isImageEdit = false;
}
function editImage() {
imageState.imageDialog = imageState.isImageEdit = true;
}
async function fetchImageList(id: string, selectedName: string) {
const res = await institutionStore.fetchImageListById(id);
imageList.value = {
selectedImage: selectedName,
list: res.map((n: string) => `institution/${id}/image/${n}`),
};
return res;
}
async function addImage(file: File | null) {
if (!file) return;
if (!props.dataId) return;
await institutionStore.addImageList(
file,
props.dataId,
Date.now().toString(),
);
await fetchImageList(props.dataId, data.value.selectedImage || '');
}
async function removeImage(name: string) {
if (!name) return;
if (!props.dataId) return;
const targetName = name.split('/').pop() || '';
await institutionStore.deleteImageByName(props.dataId, targetName);
await fetchImageList(props.dataId, data.value.selectedImage || '');
}
async function submitImage(name: string) {
if (model.value) {
imageState.imageUrl = name;
imageState.imageDialog = false;
} else {
imageState.refreshImageState = true;
emit('submitImage', name);
}
}
function clearImageState() {
imageState.imageDialog = false;
imageFile.value = null;
onCreateImageList.value = { selectedImage: '', list: [] };
imageState.refreshImageState = false;
}
watch(
() => imageFile.value,
() => {
if (imageFile.value !== null) imageState.isImageEdit = true;
},
);
watch(
() => data.value.selectedImage,
() => {
imageState.imageUrl = `${baseUrl}/institution/${props.dataId}/image/${data.value.selectedImage}`;
imageList.value
? (imageList.value.selectedImage = data.value.selectedImage || '')
: '';
console.log(imageState.imageUrl);
imageState.refreshImageState = false;
},
);
watch(
() => drawerModel.value,
async () => {
if (drawerModel.value) {
await fetchImageList(props.dataId, data.value.selectedImage || '');
imageState.imageUrl = `${baseUrl}/institution/${props.dataId}/image/${data.value.selectedImage}`;
} else {
imageList.value = { selectedImage: '', list: [] };
}
},
);
</script>
<template>
<DialogForm
@ -63,7 +182,13 @@ const data = defineModel<InstitutionPayload>('data', {
:title="$t('general.add', { text: $t('agencies.title') })"
v-model:modal="model"
:submit="() => $emit('submit')"
:close="() => $emit('close')"
:close="
() => {
imageState.imageUrl = '';
clearImageState();
$emit('close');
}
"
>
<div
:class="{
@ -72,24 +197,18 @@ const data = defineModel<InstitutionPayload>('data', {
}"
>
<ProfileBanner
no-image-action
readonly
active
hide-fade
hide-active
:icon="'ph-building-office'"
:img="imageState.imageUrl || null"
:title="data.name"
:caption="data.code"
:color="`hsla(var(--green-8-hsl)/1)`"
:bg-color="`hsla(var(--green-8-hsl)/0.1)`"
@view="viewImage"
@edit="editImage"
/>
<!-- v-model:toggle-status="currentStatusGroupType"
@update:toggle-status="
() => {
currentStatusGroupType =
currentStatusGroupType === 'CREATED' ? 'INACTIVE' : 'CREATED';
}
" -->
</div>
<div
@ -177,7 +296,12 @@ const data = defineModel<InstitutionPayload>('data', {
:title="data.name"
v-model:drawerOpen="drawerModel"
:submit="() => $emit('submit')"
:close="() => $emit('close')"
:close="
() => {
clearImageState();
$emit('close');
}
"
>
<div class="col column full-height">
<div
@ -187,8 +311,6 @@ const data = defineModel<InstitutionPayload>('data', {
}"
>
<ProfileBanner
no-image-action
readonly
active
hide-fade
hide-active
@ -197,6 +319,13 @@ const data = defineModel<InstitutionPayload>('data', {
:caption="data.code"
:color="`hsla(var(${'--green-8'}-hsl)/1)`"
:bg-color="`hsla(var(${'--green-8'}-hsl)/0.1)`"
:img="
`${baseUrl}/institution/${dataId}/image/${data.selectedImage}`.concat(
imageState.refreshImageState ? `?ts=${Date.now()}` : '',
) || null
"
@view="viewImage"
@edit="editImage"
/>
</div>
@ -330,5 +459,39 @@ const data = defineModel<InstitutionPayload>('data', {
</div>
</div>
</DrawerInfo>
<ImageUploadDialog
v-model:dialog-state="imageState.imageDialog"
v-model:file="imageFile"
v-model:on-create-data-list="onCreateImageList"
v-model:image-url="imageState.imageUrl"
v-model:data-list="imageList"
:on-create="model"
:hiddenFooter="!imageState.isImageEdit"
@add-image="addImage"
@remove-image="removeImage"
@submit="submitImage"
>
<template #title>
<span v-if="!model" class="justify-center flex text-bold">
{{ $t('general.image') }}
{{ $i18n.locale === 'eng' ? data.nameEN : data.name }}
</span>
</template>
<template #error>
<div class="full-height full-width" style="background: white">
<div
class="full-height full-width flex justify-center items-center"
style="
background: hsla(var(--green-8-hsl) / 0.1);
color: hsla(var(--green-8-hsl) / 1);
"
>
<Icon width="3rem" icon="ph-building-office" />
</div>
</div>
</template>
</ImageUploadDialog>
</template>
<style scoped></style>