feat: add QR code upload functionality and enhance bank management logic
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 7s

This commit is contained in:
puriphatt 2025-04-24 17:59:11 +07:00
parent dfc17e9623
commit ef81522561
4 changed files with 157 additions and 22 deletions

View file

@ -177,7 +177,7 @@ watch(
<div <div
v-if="!single" v-if="!single"
class="bordered q-mr-sm rounded col text-center overflow-hidden" class="bordered q-mr-sm rounded col-4 text-center overflow-hidden"
:class="{ 'pointer-none': readonly, 'q-my-sm': $q.screen.lt.md }" :class="{ 'pointer-none': readonly, 'q-my-sm': $q.screen.lt.md }"
> >
<ImageHover <ImageHover

View file

@ -21,6 +21,7 @@ import {
import AddressForm from 'src/components/form/AddressForm.vue'; import AddressForm from 'src/components/form/AddressForm.vue';
import ImageUploadDialog from 'src/components/ImageUploadDialog.vue'; import ImageUploadDialog from 'src/components/ImageUploadDialog.vue';
import { BankBook } from 'src/stores/branch/types'; import { BankBook } from 'src/stores/branch/types';
import QrCodeUploadDialog from 'src/components/QrCodeUploadDialog.vue';
const institutionStore = useInstitution(); const institutionStore = useInstitution();
@ -33,6 +34,10 @@ const imageListOnCreate = defineModel<{
selectedImage: string; selectedImage: string;
list: { url: string; imgFile: File | null; name: string }[]; list: { url: string; imgFile: File | null; name: string }[];
}>('imageListOnCreate', { default: { selectedImage: '', list: [] } }); }>('imageListOnCreate', { default: { selectedImage: '', list: [] } });
const deletesStatusQrCodeBankImag = defineModel<number[]>(
'deletesStatusQrCodeBankImag',
{ default: [] },
);
const imageState = reactive({ const imageState = reactive({
imageDialog: false, imageDialog: false,
@ -45,6 +50,14 @@ const imageState = reactive({
const imageFile = ref<File | null>(null); const imageFile = ref<File | null>(null);
const imageList = ref<{ selectedImage: string; list: string[] }>(); const imageList = ref<{ selectedImage: string; list: string[] }>();
const qrCodeDialog = ref(false);
const qrCodeImageUrl = ref<string>('');
const currentIndexQrCodeBank = ref<number>(-1);
const statusQrCodeFile = ref<File | undefined>(undefined);
const refQrCodeUpload = ref();
const statusQrCodeUrl = ref<string>('');
const statusDeletesQrCode = ref<boolean>(false);
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
readonly?: boolean; readonly?: boolean;
@ -163,6 +176,35 @@ function clearImageState() {
imageState.refreshImageState = false; imageState.refreshImageState = false;
} }
function triggerEditQrCodeBank(opts?: { save?: boolean }) {
if (opts?.save === undefined) {
qrCodeDialog.value = true;
statusDeletesQrCode.value = false;
statusQrCodeUrl.value =
formBankBook.value[currentIndexQrCodeBank.value].bankUrl || '';
statusDeletesQrCode.value = false;
} else {
formBankBook.value[currentIndexQrCodeBank.value].bankUrl =
statusQrCodeUrl.value;
formBankBook.value[currentIndexQrCodeBank.value].bankQr =
statusQrCodeFile.value;
if (statusDeletesQrCode.value === true) {
deletesStatusQrCodeBankImag.value.push(currentIndexQrCodeBank.value);
}
if (statusDeletesQrCode.value === false) {
deletesStatusQrCodeBankImag.value =
deletesStatusQrCodeBankImag.value.filter(
(item) => item !== currentIndexQrCodeBank.value,
);
}
currentIndexQrCodeBank.value = -1;
statusDeletesQrCode.value = false;
}
}
watch( watch(
() => imageFile.value, () => imageFile.value,
() => { () => {
@ -177,7 +219,6 @@ watch(
imageList.value imageList.value
? (imageList.value.selectedImage = data.value.selectedImage || '') ? (imageList.value.selectedImage = data.value.selectedImage || '')
: ''; : '';
console.log(imageState.imageUrl);
imageState.refreshImageState = false; imageState.refreshImageState = false;
}, },
); );
@ -327,8 +368,19 @@ watch(
title="agencies.bankInfo" title="agencies.bankInfo"
class="q-pt-xl" class="q-pt-xl"
dense dense
single
v-model:bank-book-list="formBankBook" v-model:bank-book-list="formBankBook"
@view-qr="
(i) => {
currentIndexQrCodeBank = i;
triggerEditQrCodeBank();
}
"
@edit-qr="
(i) => {
currentIndexQrCodeBank = i;
refQrCodeUpload && refQrCodeUpload.browse();
}
"
/> />
</div> </div>
</div> </div>
@ -518,9 +570,20 @@ watch(
title="agencies.bankInfo" title="agencies.bankInfo"
class="q-pt-xl" class="q-pt-xl"
dense dense
single
:readonly :readonly
v-model:bank-book-list="formBankBook" v-model:bank-book-list="formBankBook"
@view-qr="
(i) => {
currentIndexQrCodeBank = i;
triggerEditQrCodeBank();
}
"
@edit-qr="
(i) => {
currentIndexQrCodeBank = i;
refQrCodeUpload && refQrCodeUpload.browse();
}
"
/> />
</div> </div>
</div> </div>
@ -561,5 +624,31 @@ watch(
</div> </div>
</template> </template>
</ImageUploadDialog> </ImageUploadDialog>
<QrCodeUploadDialog
ref="refQrCodeUpload"
v-model:dialog-state="qrCodeDialog"
v-model:file="statusQrCodeFile as File"
v-model:image-url="statusQrCodeUrl"
@save="
(_file) => {
qrCodeDialog = false;
if (currentIndexQrCodeBank !== -1) {
triggerEditQrCodeBank({ save: true });
}
}
"
@clear="statusDeletesQrCode = true"
clearButton
>
<template #error>
<div
class="full-width full-height flex items-center justify-center"
style="color: gray"
>
<q-icon size="15rem" name="mdi-qrcode" />
</div>
</template>
</QrCodeUploadDialog>
</template> </template>
<style scoped></style> <style scoped></style>

View file

@ -81,7 +81,7 @@ const pageState = reactive({
isDrawerEdit: true, isDrawerEdit: true,
searchDate: [], searchDate: [],
}); });
const deletesStatusQrCodeBankImag = ref<number[]>([]);
const blankFormData: InstitutionPayload = { const blankFormData: InstitutionPayload = {
group: '', group: '',
code: '', code: '',
@ -177,16 +177,15 @@ function assignFormData(data: Institution) {
contactEmail: data.contactEmail, contactEmail: data.contactEmail,
contactName: data.contactName, contactName: data.contactName,
contactTel: data.contactTel, contactTel: data.contactTel,
bank: [ bank: data.bank.map((v) => ({
{ bankName: v.bankName,
bankName: data.bank[0]?.bankName, accountNumber: v.accountNumber,
accountNumber: data.bank[0]?.accountNumber, bankBranch: v.bankBranch,
bankBranch: data.bank[0]?.bankBranch, accountName: v.accountName,
accountName: data.bank[0]?.accountName, accountType: v.accountType,
accountType: data.bank[0]?.accountType, currentlyUse: v.currentlyUse,
currentlyUse: data.bank[0]?.currentlyUse, bankUrl: `${baseUrl}/institution/${data.id}/bank-qr/${v.id}?ts=${Date.now()}`,
}, })),
],
}; };
} }
@ -212,14 +211,10 @@ async function submit(opt?: { selectedImage: string }) {
provinceId: formData.value.provinceId, provinceId: formData.value.provinceId,
status: formData.value.status, status: formData.value.status,
bank: formData.value.bank.map((v) => ({ bank: formData.value.bank.map((v) => ({
bankName: v.bankName, ...v,
accountNumber: v.accountNumber,
bankBranch: v.bankBranch,
accountName: v.accountName,
accountType: v.accountType,
currentlyUse: v.currentlyUse,
})), })),
}; };
console.log('payload', payload);
if ( if (
(pageState.isDrawerEdit && currAgenciesData.value?.id) || (pageState.isDrawerEdit && currAgenciesData.value?.id) ||
(opt?.selectedImage && currAgenciesData.value?.id) (opt?.selectedImage && currAgenciesData.value?.id)
@ -230,6 +225,7 @@ async function submit(opt?: { selectedImage: string }) {
id: currAgenciesData.value.id, id: currAgenciesData.value.id,
selectedImage: opt?.selectedImage || undefined, selectedImage: opt?.selectedImage || undefined,
}), }),
{ indexDeleteQrCodeBank: deletesStatusQrCodeBankImag.value },
); );
if (ret) { if (ret) {
@ -982,6 +978,7 @@ watch(
v-model:data="formData" v-model:data="formData"
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"
/> />
</template> </template>
<style scoped> <style scoped>

View file

@ -75,18 +75,67 @@ export const useInstitution = defineStore('institution-store', () => {
} }
} }
if (res.data.bank && data.bank.length > 0) {
for (let i = 0; i < data.bank?.length; i++) {
if (data.bank[i].bankQr) {
await api
.put(
`/institution/${res.data.id}/bank-qr/${res.data.bank[i].id}`,
data.bank[i].bankQr,
{
headers: { 'Content-Type': data.bank[i].bankQr?.type },
onUploadProgress: (e) => console.log(e),
},
)
.catch((e) => console.error(e));
}
}
}
if (res.status < 400) { if (res.status < 400) {
return res.data; return res.data;
} }
return null; return null;
} }
async function editInstitution(data: InstitutionPayload & { id: string }) { async function editInstitution(
data: InstitutionPayload & { id: string },
opts?: { indexDeleteQrCodeBank?: number[] },
) {
const res = await api.put(`/institution/${data.id}`, { const res = await api.put(`/institution/${data.id}`, {
...data, ...data,
id: undefined, id: undefined,
group: undefined, group: undefined,
}); });
if (!!res.data.bank && !!data.bank.length) {
for (let i = 0; i < data.bank?.length; i++) {
if (data.bank[i].bankQr) {
console.log(i);
console.log(data.bank[i].bankQr);
await api
.put(
`/institution/${res.data.id}/bank-qr/${res.data.bank[i].id}`,
data.bank[i].bankQr,
{
headers: { 'Content-Type': data.bank[i].bankQr?.type },
onUploadProgress: (e) => console.log(e),
},
)
.catch((e) => console.error(e));
}
}
}
if (opts.indexDeleteQrCodeBank && opts.indexDeleteQrCodeBank.length > 0) {
console.log('delete');
opts.indexDeleteQrCodeBank.forEach(async (i) => {
await api
.delete(`/institution/${res.data.id}/bank-qr/${res.data.bank[i].id}`)
.catch((e) => console.error(e));
});
}
if (res.status < 400) { if (res.status < 400) {
return res.data; return res.data;
} }