feat: institution attachment
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 5s
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 5s
This commit is contained in:
parent
da52bfbcbd
commit
b977f86de9
6 changed files with 179 additions and 2 deletions
|
|
@ -1,6 +1,10 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
import SelectInput from '../shared/SelectInput.vue';
|
import SelectInput from '../shared/SelectInput.vue';
|
||||||
import useOptionStore from 'src/stores/options';
|
import useOptionStore from 'src/stores/options';
|
||||||
|
import { Icon } from '@iconify/vue/dist/iconify.js';
|
||||||
|
import { useInstitution } from 'src/stores/institution';
|
||||||
|
|
||||||
const optionStore = useOptionStore();
|
const optionStore = useOptionStore();
|
||||||
|
|
||||||
|
|
@ -10,6 +14,11 @@ defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
onDrawer?: boolean;
|
onDrawer?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'deleteAttachment', name: string): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const attachmentRef = ref();
|
||||||
|
|
||||||
const group = defineModel('group', { default: '' });
|
const group = defineModel('group', { default: '' });
|
||||||
const name = defineModel('name', { default: '' });
|
const name = defineModel('name', { default: '' });
|
||||||
|
|
@ -17,8 +26,19 @@ const nameEn = defineModel('nameEn', { default: '' });
|
||||||
const contactName = defineModel('contactName', { default: '' });
|
const contactName = defineModel('contactName', { default: '' });
|
||||||
const email = defineModel('email', { default: '' });
|
const email = defineModel('email', { default: '' });
|
||||||
const contactTel = defineModel('contactTel', { default: '' });
|
const contactTel = defineModel('contactTel', { default: '' });
|
||||||
|
const attachment = defineModel<File[]>('attachment');
|
||||||
|
const attachmentList =
|
||||||
|
defineModel<{ name: string; url: string }[]>('attachmentList');
|
||||||
|
|
||||||
type Options = { label: string; value: string };
|
type Options = { label: string; value: string };
|
||||||
|
|
||||||
|
function openNewTab(url: string) {
|
||||||
|
window.open(url, '_blank');
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteAttachment(name: string) {
|
||||||
|
emit('deleteAttachment', name);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="row col-12">
|
<div class="row col-12">
|
||||||
|
|
@ -162,6 +182,77 @@ type Options = { label: string; value: string };
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
||||||
|
<q-file
|
||||||
|
ref="attachmentRef"
|
||||||
|
for="input-attachment"
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
:readonly="readonly"
|
||||||
|
multiple
|
||||||
|
append
|
||||||
|
:label="$t('personnel.form.attachment')"
|
||||||
|
class="col"
|
||||||
|
v-model="attachment"
|
||||||
|
>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<Icon
|
||||||
|
icon="material-symbols:attach-file"
|
||||||
|
width="20px"
|
||||||
|
style="color: var(--brand-1)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-slot:file="file">
|
||||||
|
<div class="row full-width items-center">
|
||||||
|
<span class="col ellipsis">
|
||||||
|
{{ file.file.name }}
|
||||||
|
</span>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
flat
|
||||||
|
padding="2 2"
|
||||||
|
class="app-text-muted"
|
||||||
|
icon="mdi-close-circle"
|
||||||
|
@click.stop="attachmentRef.removeAtIndex(file.index)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-file>
|
||||||
|
|
||||||
|
<div v-if="attachmentList && attachmentList?.length > 0" class="col-12">
|
||||||
|
<q-list bordered separator class="rounded" style="padding: 0">
|
||||||
|
<q-item
|
||||||
|
id="attachment-file"
|
||||||
|
for="attachment-file"
|
||||||
|
v-for="item in attachmentList"
|
||||||
|
clickable
|
||||||
|
:key="item.url"
|
||||||
|
class="items-center row"
|
||||||
|
@click="() => openNewTab(item.url)"
|
||||||
|
>
|
||||||
|
<q-item-section>
|
||||||
|
<div class="row items-center justify-between">
|
||||||
|
<div class="col">
|
||||||
|
{{ item.name }}
|
||||||
|
</div>
|
||||||
|
<q-btn
|
||||||
|
v-if="!readonly"
|
||||||
|
id="delete-file"
|
||||||
|
rounded
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
unelevated
|
||||||
|
size="md"
|
||||||
|
icon="mdi-trash-can-outline"
|
||||||
|
class="app-text-negative"
|
||||||
|
@click.stop="deleteAttachment(item.name)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -928,6 +928,7 @@ export default {
|
||||||
contactName: 'Contact Person',
|
contactName: 'Contact Person',
|
||||||
contactTel: 'Contact Number',
|
contactTel: 'Contact Number',
|
||||||
bankInfo: 'Bank Information',
|
bankInfo: 'Bank Information',
|
||||||
|
attachment: 'Attachment',
|
||||||
},
|
},
|
||||||
|
|
||||||
requestList: {
|
requestList: {
|
||||||
|
|
|
||||||
|
|
@ -925,6 +925,7 @@ export default {
|
||||||
contactName: 'ชื่อผู้ติดต่อ',
|
contactName: 'ชื่อผู้ติดต่อ',
|
||||||
contactTel: 'เบอร์โทรผู้ติดต่อ',
|
contactTel: 'เบอร์โทรผู้ติดต่อ',
|
||||||
bankInfo: 'ข้อมูลธนาคาร',
|
bankInfo: 'ข้อมูลธนาคาร',
|
||||||
|
attachment: 'เอกสารเพิ่มเติม',
|
||||||
},
|
},
|
||||||
|
|
||||||
requestList: {
|
requestList: {
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ const emit = defineEmits<{
|
||||||
(e: 'addImage'): void;
|
(e: 'addImage'): void;
|
||||||
(e: 'removeImage'): void;
|
(e: 'removeImage'): void;
|
||||||
(e: 'submitImage', name: string): void;
|
(e: 'submitImage', name: string): void;
|
||||||
|
(e: 'deleteAttachment', name: string): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const data = defineModel<InstitutionPayload>('data', {
|
const data = defineModel<InstitutionPayload>('data', {
|
||||||
|
|
@ -121,6 +122,9 @@ const formBankBook = defineModel<BankBook[]>('formBankBook', {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
const attachment = defineModel<File[]>('attachment');
|
||||||
|
const attachmentList =
|
||||||
|
defineModel<{ name: string; url: string }[]>('attachmentList');
|
||||||
|
|
||||||
function viewImage() {
|
function viewImage() {
|
||||||
imageState.imageDialog = true;
|
imageState.imageDialog = true;
|
||||||
|
|
@ -348,6 +352,7 @@ watch(
|
||||||
v-model:contact-name="data.contactName"
|
v-model:contact-name="data.contactName"
|
||||||
v-model:email="data.contactEmail"
|
v-model:email="data.contactEmail"
|
||||||
v-model:contact-tel="data.contactTel"
|
v-model:contact-tel="data.contactTel"
|
||||||
|
v-model:attachment="attachment"
|
||||||
/>
|
/>
|
||||||
<AddressForm
|
<AddressForm
|
||||||
id="agencies-form-address-info"
|
id="agencies-form-address-info"
|
||||||
|
|
@ -550,6 +555,9 @@ watch(
|
||||||
v-model:contact-name="data.contactName"
|
v-model:contact-name="data.contactName"
|
||||||
v-model:email="data.contactEmail"
|
v-model:email="data.contactEmail"
|
||||||
v-model:contact-tel="data.contactTel"
|
v-model:contact-tel="data.contactTel"
|
||||||
|
v-model:attachment="attachment"
|
||||||
|
:attachment-list="attachmentList"
|
||||||
|
@delete-attachment="(name) => $emit('deleteAttachment', name)"
|
||||||
/>
|
/>
|
||||||
<AddressForm
|
<AddressForm
|
||||||
id="agencies-address-info"
|
id="agencies-address-info"
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,8 @@ const blankFormData: InstitutionPayload = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const attachment = ref<File[]>([]);
|
||||||
|
const attachmentList = ref<{ name: string; url: string }[]>([]);
|
||||||
const statusFilter = ref<'all' | 'statusACTIVE' | 'statusINACTIVE'>('all');
|
const statusFilter = ref<'all' | 'statusACTIVE' | 'statusINACTIVE'>('all');
|
||||||
const refAgenciesDialog = ref();
|
const refAgenciesDialog = ref();
|
||||||
const formData = ref<InstitutionPayload>(structuredClone(blankFormData));
|
const formData = ref<InstitutionPayload>(structuredClone(blankFormData));
|
||||||
|
|
@ -145,6 +147,8 @@ function resetForm() {
|
||||||
pageState.addModal = false;
|
pageState.addModal = false;
|
||||||
pageState.viewDrawer = false;
|
pageState.viewDrawer = false;
|
||||||
currAgenciesData.value = undefined;
|
currAgenciesData.value = undefined;
|
||||||
|
attachment.value = [];
|
||||||
|
attachmentList.value = [];
|
||||||
formData.value = structuredClone(blankFormData);
|
formData.value = structuredClone(blankFormData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,7 +158,7 @@ function undo() {
|
||||||
pageState.isDrawerEdit = false;
|
pageState.isDrawerEdit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function assignFormData(data: Institution) {
|
async function assignFormData(data: Institution) {
|
||||||
currAgenciesData.value = data;
|
currAgenciesData.value = data;
|
||||||
formData.value = {
|
formData.value = {
|
||||||
group: data.group,
|
group: data.group,
|
||||||
|
|
@ -187,6 +191,8 @@ function assignFormData(data: Institution) {
|
||||||
bankUrl: `${baseUrl}/institution/${data.id}/bank-qr/${v.id}?ts=${Date.now()}`,
|
bankUrl: `${baseUrl}/institution/${data.id}/bank-qr/${v.id}?ts=${Date.now()}`,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
await fetchAttachment();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submit(opt?: { selectedImage: string }) {
|
async function submit(opt?: { selectedImage: string }) {
|
||||||
|
|
@ -228,18 +234,29 @@ async function submit(opt?: { selectedImage: string }) {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
attachment.value.forEach(async (file) => {
|
||||||
|
await institutionStore.putAttachment({
|
||||||
|
parentId: ret.id || '',
|
||||||
|
name: file.name,
|
||||||
|
file: file,
|
||||||
|
});
|
||||||
|
});
|
||||||
pageState.isDrawerEdit = false;
|
pageState.isDrawerEdit = false;
|
||||||
currAgenciesData.value = ret;
|
currAgenciesData.value = ret;
|
||||||
formData.value.selectedImage = ret.selectedImage;
|
formData.value.selectedImage = ret.selectedImage;
|
||||||
await fetchData($q.screen.xs);
|
await fetchData($q.screen.xs);
|
||||||
|
attachment.value = [];
|
||||||
|
|
||||||
if (refAgenciesDialog.value && opt?.selectedImage) {
|
if (refAgenciesDialog.value && opt?.selectedImage) {
|
||||||
refAgenciesDialog.value.clearImageState();
|
refAgenciesDialog.value.clearImageState();
|
||||||
}
|
}
|
||||||
|
setTimeout(async () => {
|
||||||
|
await fetchAttachment();
|
||||||
|
}, 300);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await institutionStore.createInstitution(
|
const res = await institutionStore.createInstitution(
|
||||||
{
|
{
|
||||||
...payload,
|
...payload,
|
||||||
code: formData.value.group || '',
|
code: formData.value.group || '',
|
||||||
|
|
@ -247,6 +264,16 @@ async function submit(opt?: { selectedImage: string }) {
|
||||||
imageListOnCreate.value,
|
imageListOnCreate.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!res) return;
|
||||||
|
|
||||||
|
attachment.value.forEach(async (file) => {
|
||||||
|
await institutionStore.putAttachment({
|
||||||
|
parentId: res.id || '',
|
||||||
|
name: file.name,
|
||||||
|
file: file,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
await fetchData($q.screen.xs);
|
await fetchData($q.screen.xs);
|
||||||
pageState.addModal = false;
|
pageState.addModal = false;
|
||||||
return;
|
return;
|
||||||
|
|
@ -346,6 +373,49 @@ async function changeStatus(id?: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function deleteAttachment(attachmentName: string) {
|
||||||
|
dialog({
|
||||||
|
color: 'negative',
|
||||||
|
icon: 'mdi-trash-can-outline',
|
||||||
|
title: t('dialog.title.confirmDelete', {
|
||||||
|
msg: t('personnel.form.attachment'),
|
||||||
|
}),
|
||||||
|
actionText: t('general.delete'),
|
||||||
|
persistent: true,
|
||||||
|
message: t('dialog.message.confirmDelete'),
|
||||||
|
action: async () => {
|
||||||
|
if (!currAgenciesData.value?.id) return;
|
||||||
|
institutionStore.delAttachment({
|
||||||
|
parentId: currAgenciesData.value?.id,
|
||||||
|
name: attachmentName,
|
||||||
|
});
|
||||||
|
setTimeout(async () => {
|
||||||
|
await fetchAttachment();
|
||||||
|
}, 300);
|
||||||
|
},
|
||||||
|
cancel: () => {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchAttachment() {
|
||||||
|
const resAttachment = await institutionStore.listAttachment({
|
||||||
|
parentId: currAgenciesData.value.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!resAttachment) return;
|
||||||
|
|
||||||
|
attachmentList.value = await Promise.all(
|
||||||
|
resAttachment.map(async (f) => ({
|
||||||
|
name: f,
|
||||||
|
url: await institutionStore.getAttachment({
|
||||||
|
parentId: currAgenciesData.value.id,
|
||||||
|
name: f,
|
||||||
|
download: false,
|
||||||
|
}),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
navigatorStore.current.title = 'agencies.title';
|
navigatorStore.current.title = 'agencies.title';
|
||||||
navigatorStore.current.path = [{ text: 'agencies.caption', i18n: true }];
|
navigatorStore.current.path = [{ text: 'agencies.caption', i18n: true }];
|
||||||
|
|
@ -976,6 +1046,7 @@ watch(
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
@change-status="triggerChangeStatus"
|
@change-status="triggerChangeStatus"
|
||||||
|
@delete-attachment="deleteAttachment"
|
||||||
:readonly="!pageState.isDrawerEdit"
|
:readonly="!pageState.isDrawerEdit"
|
||||||
:isEdit="pageState.isDrawerEdit"
|
:isEdit="pageState.isDrawerEdit"
|
||||||
:hide-action="!canAccess('agencies', 'edit')"
|
:hide-action="!canAccess('agencies', 'edit')"
|
||||||
|
|
@ -985,6 +1056,8 @@ watch(
|
||||||
v-model:form-bank-book="formData.bank"
|
v-model:form-bank-book="formData.bank"
|
||||||
v-model:image-list-on-create="imageListOnCreate"
|
v-model:image-list-on-create="imageListOnCreate"
|
||||||
v-model:deletes-status-qr-code-bank-imag="deletesStatusQrCodeBankImag"
|
v-model:deletes-status-qr-code-bank-imag="deletesStatusQrCodeBankImag"
|
||||||
|
v-model:attachment="attachment"
|
||||||
|
:attachment-list="attachmentList"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,11 @@ import { api } from 'src/boot/axios';
|
||||||
import { PaginationResult } from 'src/types';
|
import { PaginationResult } from 'src/types';
|
||||||
import useFlowStore from '../flow';
|
import useFlowStore from '../flow';
|
||||||
import { Status } from '../types';
|
import { Status } from '../types';
|
||||||
|
import { baseUrl, manageAttachment, manageFile, manageMeta } from '../utils';
|
||||||
|
|
||||||
export const useInstitution = defineStore('institution-store', () => {
|
export const useInstitution = defineStore('institution-store', () => {
|
||||||
const flowStore = useFlowStore();
|
const flowStore = useFlowStore();
|
||||||
|
const attachmentManager = manageAttachment(api, 'institution');
|
||||||
|
|
||||||
const data = ref<Institution[]>([]);
|
const data = ref<Institution[]>([]);
|
||||||
const page = ref<number>(1);
|
const page = ref<number>(1);
|
||||||
|
|
@ -200,6 +202,7 @@ export const useInstitution = defineStore('institution-store', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
...attachmentManager,
|
||||||
data,
|
data,
|
||||||
page,
|
page,
|
||||||
pageMax,
|
pageMax,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue