jws-frontend/src/pages/05_quotation/preview/ViewForm.vue

768 lines
19 KiB
Vue
Raw Normal View History

2024-10-16 18:03:50 +07:00
<script lang="ts" setup>
2024-10-18 10:42:47 +07:00
import { storeToRefs } from 'pinia';
2024-12-25 11:58:24 +07:00
import { onMounted, nextTick, ref, watch } from 'vue';
2024-10-18 10:42:47 +07:00
import { precisionRound } from 'src/utils/arithmetic';
2025-02-24 17:30:29 +07:00
import { useI18n } from 'vue-i18n';
2024-10-17 18:00:16 +07:00
import ThaiBahtText from 'thai-baht-text';
2024-10-17 15:20:54 +07:00
2024-10-16 18:03:50 +07:00
// NOTE: Import stores
2025-02-24 17:30:29 +07:00
import { dialogWarningClose, formatNumberDecimal } from 'stores/utils';
2024-10-18 10:42:47 +07:00
import { useConfigStore } from 'stores/config';
2024-10-18 12:01:07 +07:00
import useBranchStore from 'stores/branch';
import { baseUrl } from 'stores/utils';
2024-10-21 12:03:19 +07:00
import useCustomerStore from 'stores/customer';
import { useQuotationStore } from 'src/stores/quotations';
2024-10-17 15:20:54 +07:00
2024-10-16 18:03:50 +07:00
// NOTE Import Types
2024-10-21 12:03:19 +07:00
import { CustomerBranch } from 'stores/customer/types';
2024-10-18 12:07:13 +07:00
import { BankBook, Branch } from 'stores/branch/types';
2024-10-18 16:23:44 +07:00
import {
QuotationPayload,
Details,
QuotationFull,
2025-01-29 16:03:27 +07:00
ProductRelation,
2024-10-18 16:23:44 +07:00
} from 'src/stores/quotations/types';
2024-10-17 15:20:54 +07:00
2024-10-16 18:03:50 +07:00
// NOTE: Import Components
2024-12-25 11:58:11 +07:00
import ViewPDF from './ViewPdf.vue';
2024-10-16 18:03:50 +07:00
import ViewHeader from './ViewHeader.vue';
2024-10-18 11:41:35 +07:00
import ViewFooter from './ViewFooter.vue';
2024-10-17 15:20:54 +07:00
import BankComponents from './BankComponents.vue';
2024-10-18 11:16:29 +07:00
import PrintButton from 'src/components/button/PrintButton.vue';
2025-02-24 17:30:29 +07:00
import { CancelButton } from 'components/button';
2024-11-27 14:27:02 +07:00
import { convertTemplate } from 'src/utils/string-template';
2024-10-17 12:55:22 +07:00
2024-10-18 10:42:47 +07:00
const configStore = useConfigStore();
2024-10-18 12:01:07 +07:00
const branchStore = useBranchStore();
2024-10-21 12:03:19 +07:00
const customerStore = useCustomerStore();
const quotationStore = useQuotationStore();
2025-02-24 17:30:29 +07:00
const { t } = useI18n();
2024-10-18 10:42:47 +07:00
const { data: config } = storeToRefs(configStore);
2024-10-17 12:55:22 +07:00
2024-10-17 18:00:16 +07:00
type Product = {
id: string;
code: string;
detail: string;
amount: number;
2025-01-29 16:03:27 +07:00
pricePerUnit: number;
2024-10-17 18:00:16 +07:00
discount: number;
vat: number;
value: number;
2025-01-24 11:49:33 +07:00
calcVat: boolean;
2025-01-29 16:03:27 +07:00
product: ProductRelation;
2024-10-17 18:00:16 +07:00
};
type SummaryPrice = {
totalPrice: number;
totalDiscount: number;
vat: number;
vatExcluded: number;
finalPrice: number;
};
2024-10-21 12:03:19 +07:00
const customer = ref<CustomerBranch>();
2024-10-18 12:07:13 +07:00
const branch = ref<Branch>();
2024-10-18 11:08:19 +07:00
const productList = ref<Product[]>([]);
2024-10-18 12:01:07 +07:00
const bankList = ref<BankBook[]>([]);
2024-10-17 18:00:16 +07:00
2025-01-29 16:03:27 +07:00
const agentPrice = ref(false);
2024-10-17 12:55:22 +07:00
const elements = ref<HTMLElement[]>([]);
2024-10-17 18:00:16 +07:00
const chunks = ref<Product[][]>([[]]);
const attachmentList = ref<
{
url: string;
2024-12-25 11:58:11 +07:00
isImage?: boolean;
isPDF?: boolean;
}[]
>([]);
const data = ref<QuotationFull & { remark?: string }>();
2024-10-18 10:42:47 +07:00
const summaryPrice = ref<SummaryPrice>({
totalPrice: 0,
totalDiscount: 0,
vat: 0,
vatExcluded: 0,
finalPrice: 0,
});
2024-10-17 12:55:22 +07:00
async function fetchQuotationById(id: string) {
const res = await quotationStore.getQuotation(id);
if (res) data.value = res;
}
async function getAttachment(quotationId: string) {
const attachment = await quotationStore.listAttachment({
parentId: quotationId,
});
if (attachment) {
2024-12-25 11:58:11 +07:00
attachmentList.value = await Promise.all(
attachment.map(async (v) => {
const url = await quotationStore.getAttachment({
parentId: quotationId,
name: v,
2024-12-25 11:58:11 +07:00
});
const ft = v.substring(v.lastIndexOf('.') + 1);
return {
url,
isImage: ['png', 'jpg', 'jpeg'].includes(ft),
isPDF: ft === 'pdf',
};
}),
);
}
}
2024-10-17 12:55:22 +07:00
async function assignData() {
2024-10-17 18:00:16 +07:00
for (let i = 0; i < productList.value.length; i++) {
2024-10-17 12:55:22 +07:00
let el = elements.value.at(-1);
if (!el) return;
if (getHeight(el) < 500) {
2024-10-17 18:00:16 +07:00
chunks.value.at(-1)?.push(productList.value[i]);
2024-10-17 12:55:22 +07:00
} else {
chunks.value.push([]);
i--;
}
await nextTick();
}
}
function getHeight(el: HTMLElement) {
const shadow = document.createElement('div');
shadow.style.opacity = '0';
shadow.style.position = 'absolute';
shadow.style.top = '-999999px';
shadow.style.left = '-999999px';
shadow.style.pointerEvents = 'none';
document.body.appendChild(shadow);
shadow.appendChild(el.cloneNode(true));
const height = shadow.offsetHeight;
document.body.removeChild(shadow);
return height;
}
2024-10-18 16:23:44 +07:00
const details = ref<Details>();
2024-10-28 13:41:27 +07:00
enum View {
Quotation,
Invoice,
Payment,
Receipt,
}
const view = ref<View>(View.Quotation);
2024-10-18 16:23:44 +07:00
2024-10-17 15:20:54 +07:00
onMounted(async () => {
2024-10-28 13:41:27 +07:00
const currentDocumentType = new URL(window.location.href).searchParams.get(
'type',
);
if (currentDocumentType === 'invoice') view.value = View.Invoice;
if (currentDocumentType === 'payment') view.value = View.Payment;
if (currentDocumentType === 'receipt') view.value = View.Receipt;
2024-10-18 10:42:47 +07:00
let str =
localStorage.getItem('quotation-preview') ||
sessionStorage.getItem('quotation-preview');
if (!str) return;
const obj: QuotationPayload = JSON.parse(str);
if (obj) sessionStorage.setItem('quotation-preview', JSON.stringify(obj));
delete localStorage['quotation-preview'];
2024-10-18 12:32:55 +07:00
const parsed = JSON.parse(sessionStorage.getItem('quotation-preview') || '');
data.value = 'data' in parsed ? parsed.data : undefined;
2024-10-18 10:42:47 +07:00
2024-10-18 16:23:44 +07:00
if (data.value) {
if (!!data.value.id) {
await getAttachment(data.value.id);
await fetchQuotationById(data.value.id);
}
2024-10-21 12:03:19 +07:00
const resCustomerBranch = await customerStore.getBranchById(
data.value?.customerBranchId,
2024-10-21 12:03:19 +07:00
);
if (resCustomerBranch) {
customer.value = resCustomerBranch;
}
2025-01-29 16:03:27 +07:00
agentPrice.value = data.value.agentPrice || parsed?.meta?.agentPrice;
2024-10-18 16:23:44 +07:00
details.value = {
code: parsed?.meta?.source?.code ?? data.value?.code,
createdAt:
parsed?.meta?.source?.createdAt ??
new Date(data.value?.createdAt || ''),
createdBy:
`${parsed?.meta?.source?.createdBy?.firstName ?? ''} ${parsed?.meta?.source?.createdBy?.telephoneNo ?? ''}`.trim() ||
`${data.value?.createdBy?.firstName ?? ''} ${data.value?.createdBy?.telephoneNo ?? ''}`.trim(),
payCondition:
parsed?.meta?.source?.payCondition ?? data.value?.payCondition,
contactName: parsed?.meta?.source?.contactName ?? data.value?.contactName,
contactTel: parsed?.meta?.source?.contactTel ?? data.value?.contactTel,
workName: parsed?.meta?.source?.workName ?? data.value?.workName,
dueDate:
parsed?.meta?.source?.dueDate ?? new Date(data.value?.dueDate || ''),
worker:
parsed?.meta?.selectedWorker ??
data.value?.worker.map((v) => v.employee),
2024-10-18 16:23:44 +07:00
};
const resBranch = await branchStore.fetchById(
data.value?.registeredBranchId ?? data.value?.registeredBranchId,
2024-10-18 16:23:44 +07:00
);
if (resBranch) {
branch.value = resBranch;
bankList.value = resBranch.bank.map((v) => ({
2024-10-18 12:01:07 +07:00
...v,
2024-10-18 16:23:44 +07:00
bankUrl: `${baseUrl}/branch/${resBranch.id}/bank-qr/${v.id}?ts=${Date.now()}`,
2024-10-18 12:01:07 +07:00
}));
}
2024-10-18 11:00:49 +07:00
productList.value =
(data?.value?.productServiceList ?? data.value?.productServiceList).map(
2025-01-23 10:20:46 +07:00
(v) => {
const originalPrice = v.pricePerUnit;
const finalPriceWithVat = precisionRound(
2025-01-23 11:08:28 +07:00
originalPrice * (1 + (config.value?.vat || 0.07)),
2025-01-23 10:20:46 +07:00
);
const finalPriceNoVat =
finalPriceWithVat / (1 + (config.value?.vat || 0.07));
2025-01-24 20:57:41 +07:00
const price = finalPriceNoVat * v.amount - v.discount;
2025-01-23 10:20:46 +07:00
const vat =
(finalPriceNoVat * v.amount - v.discount) *
(config.value?.vat || 0.07);
return {
id: v.product.id,
code: v.product.code,
detail: v.product.name,
amount: v.amount || 0,
2025-01-29 16:03:27 +07:00
pricePerUnit: v.pricePerUnit || 0,
2025-01-23 10:20:46 +07:00
discount: v.discount || 0,
vat: v.vat || 0,
value: precisionRound(price + (v.product.calcVat ? vat : 0)),
2025-01-24 11:49:33 +07:00
calcVat: v.product.calcVat,
2025-01-29 16:03:27 +07:00
product: v.product,
2025-01-23 10:20:46 +07:00
};
},
) || [];
2024-10-18 10:45:54 +07:00
}
2024-10-18 10:42:47 +07:00
summaryPrice.value = (
(data?.value?.productServiceList ?? data.value?.productServiceList) ||
[]
).reduce(
2024-10-18 10:42:47 +07:00
(a, c) => {
2025-01-23 10:20:46 +07:00
const originalPrice = c.pricePerUnit;
const finalPriceWithVat = precisionRound(
2025-01-23 11:08:28 +07:00
originalPrice * (1 + (config.value?.vat || 0.07)),
2024-10-18 10:42:47 +07:00
);
2025-01-23 10:20:46 +07:00
const finalPriceNoVat =
finalPriceWithVat / (1 + (config.value?.vat || 0.07));
const price = finalPriceNoVat * c.amount;
const vat =
(finalPriceNoVat * c.amount - c.discount) * (config.value?.vat || 0.07);
2024-10-18 10:42:47 +07:00
2025-01-29 16:03:27 +07:00
const calcVat =
c.product[agentPrice.value ? 'agentPriceCalcVat' : 'calcVat'];
2024-10-18 10:42:47 +07:00
a.totalPrice = precisionRound(a.totalPrice + price);
a.totalDiscount = precisionRound(a.totalDiscount + Number(c.discount));
2025-01-29 16:03:27 +07:00
a.vat = calcVat ? precisionRound(a.vat + vat) : a.vat;
a.vatExcluded = calcVat
2024-10-18 10:42:47 +07:00
? a.vatExcluded
2025-01-24 11:49:33 +07:00
: precisionRound(a.vatExcluded + price);
2024-10-18 10:42:47 +07:00
a.finalPrice = precisionRound(
2024-10-21 15:18:52 +07:00
a.totalPrice -
a.totalDiscount +
a.vat -
Number(data.value?.discount || 0),
2024-10-18 10:42:47 +07:00
);
return a;
},
{
totalPrice: 0,
totalDiscount: 0,
vat: 0,
vatExcluded: 0,
finalPrice: 0,
},
);
2024-10-17 12:55:22 +07:00
assignData();
});
2025-01-29 16:03:27 +07:00
function calcPrice(c: Product) {
const originalPrice = c.pricePerUnit;
const finalPriceWithVat = precisionRound(
originalPrice + originalPrice * (config.value?.vat || 0.07),
);
const finalPriceNoVat = finalPriceWithVat / (1 + (config.value?.vat || 0.07));
const price = finalPriceNoVat * c.amount - c.discount;
const vat = c.product[agentPrice.value ? 'agentPriceCalcVat' : 'calcVat']
? (finalPriceNoVat * c.amount - c.discount) * (config.value?.vat || 0.07)
: 0;
return precisionRound(price + vat);
}
2025-02-24 17:30:29 +07:00
async function closeTab() {
dialogWarningClose(t, {
message: t('dialog.message.close'),
action: () => {
window.close();
},
cancel: () => {},
});
}
function closeAble() {
return window.opener !== null;
}
watch(elements, () => {});
2024-10-18 11:16:29 +07:00
function print() {
window.print();
}
2024-10-16 18:03:50 +07:00
</script>
<template>
2024-10-18 11:16:29 +07:00
<div class="toolbar">
<PrintButton solid @click="print" />
2025-02-24 17:30:29 +07:00
<CancelButton
outlined
id="btn-close"
@click="closeTab()"
:label="$t('dialog.action.close')"
v-if="closeAble()"
/>
2024-10-18 11:16:29 +07:00
</div>
2025-02-24 17:30:29 +07:00
2024-10-28 13:41:27 +07:00
<div
class="row justify-between container color-quotation"
:class="{
'color-quotation': view === View.Quotation,
'color-invoice': view === View.Invoice,
'color-receipt': view === View.Receipt,
}"
>
2024-10-17 12:55:22 +07:00
<section class="content" v-for="chunk in chunks">
2024-10-18 16:23:44 +07:00
<ViewHeader
v-if="!!branch && !!customer && !!details"
:branch="branch"
:customer="customer"
:details="details"
2024-11-01 10:11:30 +07:00
:view="view"
2024-10-18 16:23:44 +07:00
/>
2024-10-16 18:03:50 +07:00
<span
2024-10-17 09:38:33 +07:00
class="q-mb-sm q-mt-md"
2024-10-16 18:03:50 +07:00
style="
font-weight: 800;
font-size: 16px;
color: var(--main);
2024-10-16 18:03:50 +07:00
display: block;
border-bottom: 2px solid var(--main);
2024-10-16 18:03:50 +07:00
"
>
2024-10-24 16:36:46 +07:00
{{ $t('preview.productList') }}
2024-10-16 18:03:50 +07:00
</span>
2024-10-17 12:55:22 +07:00
<table ref="elements" class="q-mb-sm" cellpadding="0" style="width: 100%">
2024-10-21 15:18:52 +07:00
<tbody class="color-tr">
2024-10-16 18:03:50 +07:00
<tr>
2024-10-24 16:36:46 +07:00
<th>{{ $t('preview.rank') }}</th>
<th>{{ $t('preview.productCode') }}</th>
2024-10-17 15:51:56 +07:00
<th>{{ $t('general.detail') }}</th>
<th>{{ $t('general.amount') }}</th>
2024-10-24 16:36:46 +07:00
<th>{{ $t('preview.pricePerUnit') }}</th>
<th>{{ $t('preview.discount') }}</th>
<th>{{ $t('preview.vat') }}</th>
<th>{{ $t('preview.value') }}</th>
2024-10-16 18:03:50 +07:00
</tr>
2024-10-21 15:18:52 +07:00
<tr v-for="(v, i) in chunk">
2024-10-16 18:03:50 +07:00
<td class="text-center">{{ i + 1 }}</td>
2024-10-17 18:00:16 +07:00
<td>{{ v.code }}</td>
<td>{{ v.detail }}</td>
2024-10-18 11:08:19 +07:00
<td style="text-align: right">{{ v.amount }}</td>
<td style="text-align: right">
2025-01-29 16:03:27 +07:00
{{
formatNumberDecimal(
v.pricePerUnit +
(v.product[agentPrice ? 'agentPriceCalcVat' : 'calcVat']
? v.pricePerUnit * (config?.vat || 0.07)
: 0),
2,
)
}}
2024-10-18 11:08:19 +07:00
</td>
<td style="text-align: right">
{{ formatNumberDecimal(v.discount, 2) }}
</td>
<td style="text-align: right">
2025-01-24 11:49:33 +07:00
{{
formatNumberDecimal(
2025-01-29 16:17:19 +07:00
v.product[agentPrice ? 'agentPriceCalcVat' : 'calcVat']
2025-01-24 11:49:33 +07:00
? precisionRound(
2025-01-29 16:03:27 +07:00
(v.pricePerUnit * v.amount - v.discount) *
2025-01-24 11:49:33 +07:00
(config?.vat || 0.07),
)
: 0,
2,
)
}}
2024-10-18 11:08:19 +07:00
</td>
<td style="text-align: right">
2025-01-29 16:03:27 +07:00
{{ formatNumberDecimal(calcPrice(v), 2) }}
2024-10-18 11:08:19 +07:00
</td>
2024-10-16 18:03:50 +07:00
</tr>
</tbody>
</table>
<table
2024-10-18 17:38:46 +07:00
style="width: 40%; margin-left: auto"
2024-10-16 18:03:50 +07:00
class="q-mb-md"
cellpadding="0"
>
2024-10-21 15:18:52 +07:00
<tbody class="color-tr">
2024-10-16 18:03:50 +07:00
<tr>
2024-10-17 18:00:16 +07:00
<td>{{ $t('general.total') }}</td>
<td class="text-right">
{{ formatNumberDecimal(summaryPrice.totalPrice, 2) }}
฿
</td>
2024-10-16 18:03:50 +07:00
</tr>
2024-10-21 15:18:52 +07:00
<tr>
2024-10-17 18:00:16 +07:00
<td>{{ $t('general.discount') }}</td>
<td class="text-right">
{{ formatNumberDecimal(summaryPrice.totalDiscount, 2) || 0 }} ฿
</td>
2024-10-16 18:03:50 +07:00
</tr>
<tr>
2024-10-17 18:00:16 +07:00
<td>{{ $t('general.totalAfterDiscount') }}</td>
<td class="text-right">
{{
formatNumberDecimal(
summaryPrice.totalPrice - summaryPrice.totalDiscount,
2,
)
}}
฿
</td>
2024-10-16 18:03:50 +07:00
</tr>
2024-10-21 15:18:52 +07:00
<tr>
2024-10-17 18:00:16 +07:00
<td>{{ $t('general.totalVatExcluded') }}</td>
<td class="text-right">
{{ formatNumberDecimal(summaryPrice.vatExcluded, 2) || 0 }}
฿
</td>
2024-10-16 18:03:50 +07:00
</tr>
2024-10-21 15:18:52 +07:00
<tr>
<td>{{ $t('general.vat', { msg: '7%' }) }}</td>
<td class="text-right">
{{ formatNumberDecimal(summaryPrice.vat, 2) }} ฿
</td>
</tr>
2024-10-16 18:03:50 +07:00
<tr>
2024-10-17 18:00:16 +07:00
<td>{{ $t('general.totalVatIncluded') }}</td>
<td class="text-right">
{{
formatNumberDecimal(
2025-01-27 10:41:53 +07:00
summaryPrice.totalPrice - summaryPrice.totalDiscount,
2024-10-17 18:00:16 +07:00
2,
)
}}
฿
</td>
2024-10-16 18:03:50 +07:00
</tr>
<tr>
<td>{{ $t('general.discountAfterVat') }}</td>
<td class="text-right">
{{ formatNumberDecimal(data?.discount || 0, 2) }}
฿
</td>
</tr>
2024-10-16 18:03:50 +07:00
</tbody>
</table>
<div class="row justify-between q-mb-md" style="width: 100%">
<div
class="column set-width bg-color full-height"
2024-10-16 18:03:50 +07:00
style="padding: 12px"
>
2025-01-23 14:19:56 +07:00
({{ ThaiBahtText(summaryPrice.finalPrice) || 'ศูนย์บาทถ้วน' }})
2024-10-16 18:03:50 +07:00
</div>
<div
2024-10-18 14:11:33 +07:00
class="row text-right border-5 items-center"
style="width: 40%; background: var(--main); padding: 8px"
2024-10-16 18:03:50 +07:00
>
2025-01-20 14:23:08 +07:00
<span style="color: white; font-weight: 600">
{{ $t('quotation.totalPrice') }}
</span>
2024-10-16 18:03:50 +07:00
<span
class="border-5"
style="
width: 70%;
margin-left: auto;
background: white;
padding: 4px;
"
>
2024-10-17 18:00:16 +07:00
{{
formatNumberDecimal(Math.max(summaryPrice.finalPrice, 0), 2) || 0
}}
฿
2024-10-16 18:03:50 +07:00
</span>
</div>
</div>
</section>
<section class="content">
2024-10-18 16:23:44 +07:00
<ViewHeader
v-if="!!branch && !!customer && !!details"
:branch="branch"
:customer="customer"
:details="details"
2024-11-01 10:11:30 +07:00
:view="view"
2024-10-18 16:23:44 +07:00
/>
2024-10-16 18:03:50 +07:00
<span
2024-10-17 09:38:33 +07:00
class="q-mb-sm q-mt-md"
2024-10-16 18:03:50 +07:00
style="
font-weight: 800;
font-size: 16px;
color: var(--main);
2024-10-16 18:03:50 +07:00
display: block;
border-bottom: 2px solid var(--main);
2024-10-16 18:03:50 +07:00
"
>
2025-01-20 14:23:08 +07:00
{{ $t('general.remark') }}
2024-10-16 18:03:50 +07:00
</span>
2024-10-17 18:04:27 +07:00
<div
class="border-5 surface-0 detail-note q-mb-md"
style="width: 100%; padding: 8px 16px; white-space: pre-wrap"
>
2024-11-27 14:27:02 +07:00
<div
v-html="
convertTemplate(data?.remark || '', {
'quotation-payment': {
paymentType: data?.payCondition || 'Full',
amount: summaryPrice.finalPrice,
installments: data?.paySplit,
},
'quotation-labor': {
name:
details?.worker.map(
(v, i) =>
`${i + 1}. ` +
`${v.namePrefix}. ${v.firstNameEN} ${v.lastNameEN}`.toUpperCase(),
) || [],
},
}) || '-'
"
></div>
2024-10-16 18:03:50 +07:00
</div>
</section>
<section class="content">
2024-10-18 16:23:44 +07:00
<ViewHeader
v-if="!!branch && !!customer && !!details"
:branch="branch"
:customer="customer"
:details="details"
2024-11-01 10:11:30 +07:00
:view="view"
2024-10-18 16:23:44 +07:00
/>
2024-10-16 18:03:50 +07:00
<span
class="q-mb-sm"
style="
font-weight: 800;
font-size: 16px;
color: var(--main);
2024-10-16 18:03:50 +07:00
display: block;
border-bottom: 2px solid var(--main);
2024-10-16 18:03:50 +07:00
"
>
2025-01-20 14:23:08 +07:00
{{ $t('quotation.paymentChannels') }}
2024-10-16 18:03:50 +07:00
</span>
2024-10-18 11:41:35 +07:00
<article style="height: 5.8in">
<BankComponents
2024-10-18 12:29:48 +07:00
v-for="(bank, index) in bankList"
:index="index"
2024-10-18 11:41:35 +07:00
:bank-book="bank"
:key="bank.id"
/>
</article>
2024-10-18 12:07:13 +07:00
<ViewFooter
:data="{
name: '',
company: branch?.name || '',
buyer: '',
buyDate: '',
approveDate: '',
approver: '',
}"
/>
2024-10-16 18:03:50 +07:00
</section>
<section
2024-12-25 11:58:11 +07:00
v-for="item in attachmentList.filter((v) => v.isImage)"
class="content"
>
2024-12-25 11:58:11 +07:00
<q-img :src="item.url" />
</section>
2024-12-25 11:58:11 +07:00
<ViewPDF
v-for="item in attachmentList.filter((v) => v.isPDF)"
:url="item.url"
/>
2024-10-16 18:03:50 +07:00
</div>
</template>
<style scoped>
.color-quotation {
--main: var(--orange-6);
--main-hsl: var(--orange-6-hsl);
}
2024-10-28 13:41:27 +07:00
.color-invoice {
--main: var(--purple-9);
--main-hsl: var(--purple-9-hsl);
}
.color-receipt {
--main: var(--green-6);
--main-hsl: var(--green-6-hsl);
}
2024-10-18 11:16:29 +07:00
.toolbar {
width: 100%;
position: sticky;
top: 0;
display: flex;
2025-02-24 17:30:29 +07:00
justify-content: space-between;
2024-10-18 11:16:29 +07:00
align-items: center;
margin-bottom: 1rem;
padding: 1rem;
background: white;
border-bottom: 1px solid var(--gray-3);
z-index: 99999;
2024-10-18 11:16:29 +07:00
}
2024-10-16 18:03:50 +07:00
table {
border-collapse: collapse;
}
th {
background: var(--main);
2024-10-16 18:03:50 +07:00
color: white;
padding: 4px;
}
td {
padding: 4px 8px;
}
.border-5 {
border-radius: 5px;
}
.set-width {
width: 50%;
}
.bg-color {
background-color: hsla(var(--main-hsl) / 0.1);
2024-10-16 18:03:50 +07:00
}
2024-10-21 15:18:52 +07:00
.color-tr > tr:nth-child(odd) {
background-color: hsla(var(--main-hsl) / 0.1);
2024-10-16 18:03:50 +07:00
}
.container {
padding: 1rem;
display: flex;
gap: 1rem;
margin-inline: auto;
2024-10-17 09:34:30 +07:00
background: var(--gray-3);
width: calc(8.3in + 1rem);
2024-10-16 18:03:50 +07:00
}
.container :deep(*) {
font-size: 95%;
}
2024-10-17 12:55:22 +07:00
2024-12-25 11:58:11 +07:00
.content {
2024-10-16 18:03:50 +07:00
width: 100%;
2024-10-17 09:34:30 +07:00
padding: 0.5in;
2024-10-16 18:03:50 +07:00
align-items: center;
background: white;
page-break-after: always;
break-after: page;
2024-10-18 11:48:13 +07:00
height: 11.7in;
max-height: 11.7in;
2024-10-16 18:03:50 +07:00
}
2024-10-16 18:03:50 +07:00
.position-bottom {
margin-top: auto;
}
2024-10-16 18:03:50 +07:00
.detail-note {
display: flex;
flex-direction: column;
gap: 8px;
& > * {
display: flex;
flex-direction: column;
}
}
hr {
border-style: solid;
border-color: var(--main);
2024-10-16 18:03:50 +07:00
}
@media print {
2024-10-18 11:16:29 +07:00
.toolbar {
display: none;
}
2024-10-16 18:03:50 +07:00
.container {
padding: 0;
gap: 0;
width: 100%;
2024-10-17 09:38:33 +07:00
background: white;
2024-10-16 18:03:50 +07:00
}
2024-10-17 09:34:30 +07:00
.content {
padding: 0;
height: unset;
2024-10-17 09:34:30 +07:00
}
2024-10-16 18:03:50 +07:00
}
</style>