feat: quotation attachment (#49)
* fix: i18n * fix: 18n * feat: file upload component * feat: quotation attachment --------- Co-authored-by: puriphatt <puriphat@frappet.com>
This commit is contained in:
parent
7817f8bd40
commit
0ef389c69b
5 changed files with 235 additions and 3 deletions
|
|
@ -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<number[]>([]);
|
|||
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<Record<string, any>>();
|
||||
|
||||
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>(View.Quotation);
|
|||
</div>
|
||||
</q-expansion-item>
|
||||
|
||||
<q-expansion-item
|
||||
for="item-up"
|
||||
id="item-up"
|
||||
dense
|
||||
class="overflow-hidden"
|
||||
switch-toggle-side
|
||||
default-opened
|
||||
style="border-radius: var(--radius-2)"
|
||||
expand-icon="mdi-chevron-down-circle"
|
||||
header-class="surface-1"
|
||||
>
|
||||
<template v-slot:header>
|
||||
<section class="row items-center full-width">
|
||||
<div class="row items-center q-pr-md q-py-sm">
|
||||
<span
|
||||
class="text-weight-medium q-mr-md"
|
||||
style="font-size: 18px"
|
||||
>
|
||||
{{ $t('quotation.additionalFile') }}
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<div class="surface-1 q-pa-md full-width">
|
||||
<UploadFileSection
|
||||
:readonly="view !== View.Quotation && view !== View.Invoice"
|
||||
v-model:file-data="attachmentData"
|
||||
:label="
|
||||
$t('general.upload', { msg: $t('general.attachment') })
|
||||
"
|
||||
:transform-url="
|
||||
async (url: string) => {
|
||||
const result = await api.get<string>(url);
|
||||
return result.data;
|
||||
}
|
||||
"
|
||||
@update:file="(f) => uploadAttachment(f)"
|
||||
@close="(v) => triggerDelete(v)"
|
||||
/>
|
||||
</div>
|
||||
</q-expansion-item>
|
||||
|
||||
<q-expansion-item
|
||||
for="item-up"
|
||||
id="item-up"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue