diff --git a/src/components/upload-file/UploadFileSection.vue b/src/components/upload-file/UploadFileSection.vue new file mode 100644 index 00000000..27839ecc --- /dev/null +++ b/src/components/upload-file/UploadFileSection.vue @@ -0,0 +1,108 @@ + + + diff --git a/src/i18n/eng.ts b/src/i18n/eng.ts index c97f1cb8..69594b8a 100644 --- a/src/i18n/eng.ts +++ b/src/i18n/eng.ts @@ -701,6 +701,7 @@ export default { paySplitCount: 'Number of Installments', payTotal: 'Total {msg}', customerAcceptance: 'Customer Acceptance', + additionalFile: 'Attachment File', paySplitMessage: 'Amount to be paid (Baht)', summary: 'Total Summary', diff --git a/src/i18n/tha.ts b/src/i18n/tha.ts index ecd3cef1..47e1db66 100644 --- a/src/i18n/tha.ts +++ b/src/i18n/tha.ts @@ -693,6 +693,7 @@ export default { selectInvoice: 'เลือกใบแจ้งหนี้', approveInvoice: 'อนุมัติใบแจ้งหนี้', customerAcceptance: 'ลูกค้าตอบรับ', + additionalFile: 'ไฟล์เอกสารเพิ่มเติม', paymentCondition: 'เงื่อนไขการชำระเงิน', payType: 'วิธีการชำระเงิน', diff --git a/src/pages/05_quotation/QuotationForm.vue b/src/pages/05_quotation/QuotationForm.vue index abd88e6f..aebd3531 100644 --- a/src/pages/05_quotation/QuotationForm.vue +++ b/src/pages/05_quotation/QuotationForm.vue @@ -13,6 +13,7 @@ import { ProductTree, quotationProductTree } from './utils'; // NOTE: Import stores import { setLocale, dateFormat, calculateAge } from 'src/utils/datetime'; import { useEmployeeForm } from 'src/pages/03_customer-management/form'; +import { useQuotationStore } from 'src/stores/quotations'; import useProductServiceStore from 'stores/product-service'; import { baseUrl, @@ -71,6 +72,7 @@ import { uploadFileListEmployee, columnsAttachment, } from 'src/pages/03_customer-management/constant'; +import UploadFileSection from 'src/components/upload-file/UploadFileSection.vue'; import { columnPaySplit } from './constants'; import { precisionRound } from 'src/utils/arithmetic'; @@ -78,6 +80,7 @@ import { useConfigStore } from 'src/stores/config'; import QuotationFormMetadata from './QuotationFormMetadata.vue'; import BadgeComponent from 'src/components/BadgeComponent.vue'; import PaymentForm from './PaymentForm.vue'; +import { api } from 'src/boot/axios'; type Node = { [key: string]: any; @@ -97,6 +100,7 @@ const productServiceStore = useProductServiceStore(); const employeeFormStore = useEmployeeForm(); const customerStore = useCustomerStore(); const quotationForm = useQuotationForm(); +const quotationStore = useQuotationStore(); const optionStore = useOptionStore(); const { t, locale } = useI18n(); const ocrStore = useOcrStore(); @@ -149,6 +153,16 @@ const selectedInstallmentNo = ref([]); const selectedInstallment = ref(); const agentPrice = ref(false); +const attachmentData = ref< + { + name: string; + progress: number; + loaded: number; + total: number; + url?: string; + }[] +>([]); + function getPrice( list: typeof productServiceList.value, filterHook?: ( @@ -717,6 +731,66 @@ function changeMode(mode: string) { } } +async function triggerDelete(name: string) { + await quotationStore.delAttachment({ + parentId: quotationFormData.value.id || '', + name, + }); + await getAttachment(); +} + +async function getAttachment() { + const attachment = await quotationStore.listAttachment({ + parentId: quotationFormData.value.id || '', + }); + + if (attachment && attachment.length > 0) { + attachmentData.value = attachmentData.value.filter((item) => + attachment.includes(item.name), + ); + + attachment.forEach((v) => { + const exists = attachmentData.value.some((item) => item.name === v); + + if (!exists) { + attachmentData.value.push({ + name: v, + progress: 1, + loaded: 0, + total: 0, + url: `quotation/${quotationFormData.value.id || ''}/attachment/${v}`, + }); + } + }); + } else attachmentData.value = []; +} + +async function uploadAttachment(file?: File) { + if (!file) return; + if (!quotationFormData.value) return; + attachmentData.value.push({ + name: file.name, + progress: 0, + loaded: 0, + total: 0, + }); + + const ret = await quotationStore.putAttachment({ + parentId: quotationFormData.value.id || '', + name: file.name, + file: file, + onUploadProgress: (e) => { + attachmentData.value[attachmentData.value.length - 1] = { + name: file.name, + progress: e.progress || 0, + loaded: e.loaded, + total: e.total || 0, + }; + }, + }); + if (ret) await getAttachment(); +} + const sessionData = ref>(); onMounted(async () => { @@ -774,6 +848,7 @@ onMounted(async () => { if (locale.value === 'tha') optionStore.globalOption = rawOption.tha; await fetchStatus(); + await getAttachment(); pageState.isLoaded = true; }); @@ -1293,6 +1368,49 @@ const view = ref(View.Quotation); + + + +
+ +
+
+ { | 'BillSplitCustom'; query?: string; }) { - const res = await api.get>(`/quotation`, { + const res = await api.get>('/quotation', { params, }); if (res.status < 400) { @@ -141,6 +141,8 @@ export const useQuotationStore = defineStore('quotation-store', () => { return null; } + const fileManager = manageAttachment(api, 'quotation'); + return { data, page, @@ -154,6 +156,8 @@ export const useQuotationStore = defineStore('quotation-store', () => { editQuotation, deleteQuotation, changeStatus, + + ...fileManager, }; }); @@ -163,7 +167,7 @@ export const useQuotationStore = defineStore('quotation-store', () => { export const useQuotationPayment = defineStore('quotation-payment', () => { async function getQuotationPayment(quotationId: string) { const res = await api.get>( - `/payment`, + '/payment', { params: { quotationId } }, ); if (res.status < 400) { @@ -186,7 +190,7 @@ export const useQuotationPayment = defineStore('quotation-payment', () => { return null; } - const fileManager = manageAttachment(api, `payment`); + const fileManager = manageAttachment(api, 'payment'); return { getQuotationPayment,