Merge branch 'develop'
This commit is contained in:
commit
16e9393315
29 changed files with 299 additions and 136 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
import { calculateDaysUntilExpire } from 'stores/utils';
|
import { calculateDaysUntilExpire } from 'stores/utils';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
expirationDate: Date;
|
expirationDate?: Date | string;
|
||||||
showAllDay?: boolean;
|
showAllDay?: boolean;
|
||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -10,7 +10,7 @@ defineProps<{
|
||||||
<template>
|
<template>
|
||||||
<template
|
<template
|
||||||
v-if="
|
v-if="
|
||||||
calculateDaysUntilExpire(expirationDate) <= 90 ||
|
(expirationDate && calculateDaysUntilExpire(expirationDate) <= 90) ||
|
||||||
(expirationDate !== undefined && !!showAllDay)
|
(expirationDate !== undefined && !!showAllDay)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -74,11 +74,6 @@ type Options = { label: string; value: string };
|
||||||
class="col"
|
class="col"
|
||||||
:label="'Agencies Name'"
|
:label="'Agencies Name'"
|
||||||
v-model="nameEn"
|
v-model="nameEn"
|
||||||
:rules="[
|
|
||||||
(val: string) => !!val || $t('form.error.required'),
|
|
||||||
(val: string) =>
|
|
||||||
/^[A-Za-z0-9.,' -]+$/.test(val) || $t('form.error.letterOnly'),
|
|
||||||
]"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,10 @@ onMounted(() => {
|
||||||
@click="$emit('click')"
|
@click="$emit('click')"
|
||||||
>
|
>
|
||||||
<q-icon :name="icon" size="lg" :style="`color: ${color}`" />
|
<q-icon :name="icon" size="lg" :style="`color: ${color}`" />
|
||||||
<article class="col column q-pl-md ellipsis">
|
<article class="col column q-pl-md">
|
||||||
<span>{{ name }}</span>
|
<span class="ellipsis full-width">
|
||||||
|
{{ name }}
|
||||||
|
</span>
|
||||||
<span class="text-caption app-text-muted-2">
|
<span class="text-caption app-text-muted-2">
|
||||||
{{
|
{{
|
||||||
uploading.loaded
|
uploading.loaded
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,15 @@ import { dateFormat } from 'src/utils/datetime';
|
||||||
const isEdit = ref(false);
|
const isEdit = ref(false);
|
||||||
const allMeta = ref<Record<string, string>>();
|
const allMeta = ref<Record<string, string>>();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const currentId = defineModel<string>('currentId');
|
||||||
|
const groupList = defineModel<
|
||||||
|
{
|
||||||
|
label: string;
|
||||||
|
group: string;
|
||||||
|
value: string;
|
||||||
|
_meta?: Record<string, any>;
|
||||||
|
}[]
|
||||||
|
>('groupList');
|
||||||
const obj = defineModel<
|
const obj = defineModel<
|
||||||
{
|
{
|
||||||
_meta?: Record<string, any>;
|
_meta?: Record<string, any>;
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ function pickFile() {
|
||||||
<div
|
<div
|
||||||
v-for="(d, j) in fileData"
|
v-for="(d, j) in fileData"
|
||||||
:key="j"
|
:key="j"
|
||||||
|
class="full-width"
|
||||||
:class="{
|
:class="{
|
||||||
'q-pt-md': layout === 'row' && j === 0,
|
'q-pt-md': layout === 'row' && j === 0,
|
||||||
'q-pt-sm': j > 0,
|
'q-pt-sm': j > 0,
|
||||||
|
|
|
||||||
|
|
@ -731,6 +731,16 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
quotation: {
|
quotation: {
|
||||||
|
quotationDate: 'Quotation Date',
|
||||||
|
seller: 'Seller',
|
||||||
|
paymentChannels: 'Payment Channels',
|
||||||
|
channelsThat: 'Channels That',
|
||||||
|
bankAccountNumber: 'Bank Account Number',
|
||||||
|
bankAccountName: 'Bank Account Name',
|
||||||
|
inTheNameOf: 'In The Name Of',
|
||||||
|
productOrderer: 'Product Orderer',
|
||||||
|
approver: 'Approver',
|
||||||
|
date: 'Date',
|
||||||
tableColumnsRequest: {
|
tableColumnsRequest: {
|
||||||
code: 'Request List Code',
|
code: 'Request List Code',
|
||||||
},
|
},
|
||||||
|
|
@ -928,6 +938,12 @@ export default {
|
||||||
receive: 'Job Receipt ',
|
receive: 'Job Receipt ',
|
||||||
caption: 'All Task Order',
|
caption: 'All Task Order',
|
||||||
code: 'Task Order Code',
|
code: 'Task Order Code',
|
||||||
|
workName: 'Work Name',
|
||||||
|
contacts: 'Contacts',
|
||||||
|
inTheNameOf: 'In The Name Of',
|
||||||
|
productOrderer: 'Product Orderer',
|
||||||
|
approver: 'Approver',
|
||||||
|
date: 'Date',
|
||||||
|
|
||||||
receiveTaskOrder: 'Receive Task Order',
|
receiveTaskOrder: 'Receive Task Order',
|
||||||
tasktobeDone: 'Task to be Done',
|
tasktobeDone: 'Task to be Done',
|
||||||
|
|
@ -961,7 +977,7 @@ export default {
|
||||||
Validate: 'Validate',
|
Validate: 'Validate',
|
||||||
Complete: 'Complete',
|
Complete: 'Complete',
|
||||||
Canceled: 'Canceled',
|
Canceled: 'Canceled',
|
||||||
Restart: 'go proceed again',
|
Restart: 'Retry',
|
||||||
receive: {
|
receive: {
|
||||||
Canceled: 'Canceled',
|
Canceled: 'Canceled',
|
||||||
},
|
},
|
||||||
|
|
@ -1099,9 +1115,10 @@ export default {
|
||||||
authFailed: 'Authentication Failed. Please try again later. ',
|
authFailed: 'Authentication Failed. Please try again later. ',
|
||||||
installmentsValidateFailed:
|
installmentsValidateFailed:
|
||||||
'Validation failed. Each installment must include at least one product. Please review and update the installments accordingly.',
|
'Validation failed. Each installment must include at least one product. Please review and update the installments accordingly.',
|
||||||
flowTemplateNotFound: 'Workflow template cannot be found',
|
flowTemplateNotFound: 'Workflow template cannot be found.',
|
||||||
taskOrderNotFound: 'Task order cannot be found.',
|
taskOrderNotFound: 'Task order cannot be found.',
|
||||||
quotationNotFound: 'Quotation cannot be found.',
|
quotationNotFound: 'Quotation cannot be found.',
|
||||||
|
sameNameExists: 'Same name exists.',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -725,6 +725,16 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
quotation: {
|
quotation: {
|
||||||
|
quotationDate: 'วันที่ใบเสนอราคา',
|
||||||
|
seller: 'ผู้ขาย',
|
||||||
|
paymentChannels: 'ช่องทางชำระเงิน',
|
||||||
|
channelsThat: 'ช่องทางที่',
|
||||||
|
bankAccountNumber: 'เลขบัญชีธนาคาร',
|
||||||
|
bankAccountName: 'ชื่อบัญชี',
|
||||||
|
inTheNameOf: 'ในนาม',
|
||||||
|
productOrderer: 'ผู้สั่งซื้อสินค้า',
|
||||||
|
approver: 'ผู้อนุมัติ',
|
||||||
|
date: 'วันที่',
|
||||||
tableColumnsRequest: {
|
tableColumnsRequest: {
|
||||||
code: 'รหัสใบรายการคำขอ',
|
code: 'รหัสใบรายการคำขอ',
|
||||||
},
|
},
|
||||||
|
|
@ -736,7 +746,7 @@ export default {
|
||||||
title: 'ใบเสนอราคา',
|
title: 'ใบเสนอราคา',
|
||||||
caption: 'ใบเสนอราคาทั้งหมด',
|
caption: 'ใบเสนอราคาทั้งหมด',
|
||||||
customerName: 'ชื่อลูกค้า',
|
customerName: 'ชื่อลูกค้า',
|
||||||
actor: 'ผู้ที่ทำรายงาน',
|
actor: 'ผู้ที่ทำรายการ',
|
||||||
totalPrice: 'ยอดรวมสุทธิ',
|
totalPrice: 'ยอดรวมสุทธิ',
|
||||||
totalPriceBaht: 'ยอดรวมสุทธิ (บาท)',
|
totalPriceBaht: 'ยอดรวมสุทธิ (บาท)',
|
||||||
receipt: 'ใบเสร็จ/กำกับภาษี',
|
receipt: 'ใบเสร็จ/กำกับภาษี',
|
||||||
|
|
@ -919,6 +929,12 @@ export default {
|
||||||
receive: 'ใบรับงาน',
|
receive: 'ใบรับงาน',
|
||||||
caption: 'ใบสั่งงานทั้งหมด',
|
caption: 'ใบสั่งงานทั้งหมด',
|
||||||
code: 'เลขใบสั่งงาน',
|
code: 'เลขใบสั่งงาน',
|
||||||
|
workName: 'ชื่อใบงาน',
|
||||||
|
contacts: 'ผู้ติดต่อ',
|
||||||
|
inTheNameOf: 'ในนาม',
|
||||||
|
productOrderer: 'ผู้สั่งซื้อสินค้า',
|
||||||
|
approver: 'ผู้อนุมัติ',
|
||||||
|
date: 'วันที่',
|
||||||
|
|
||||||
receiveTaskOrder: 'รับใบสั่งงาน',
|
receiveTaskOrder: 'รับใบสั่งงาน',
|
||||||
tasktobeDone: 'งานที่ต้องทำ',
|
tasktobeDone: 'งานที่ต้องทำ',
|
||||||
|
|
@ -946,11 +962,11 @@ export default {
|
||||||
InProgress: 'กำลังดำเนินการ ',
|
InProgress: 'กำลังดำเนินการ ',
|
||||||
Success: 'ดำเนินการสำเร็จ',
|
Success: 'ดำเนินการสำเร็จ',
|
||||||
Failed: 'ดำเนินการไม่สำเร็จ',
|
Failed: 'ดำเนินการไม่สำเร็จ',
|
||||||
Redo: 'ยกเลิกรอดำเนินการใหม่',
|
Redo: 'ยกเลิกเพื่อสร้างใบใหม่',
|
||||||
Validate: 'ตรวจสอบความถูกต้อง',
|
Validate: 'ตรวจสอบความถูกต้อง',
|
||||||
Complete: 'ดำเนินการเสร็จสิ้น',
|
Complete: 'ดำเนินการเสร็จสิ้น',
|
||||||
Canceled: 'รายการคำขอถูกยกเลิก',
|
Canceled: 'รายการคำขอถูกยกเลิก',
|
||||||
Restart: 'ไปดำเนินการใหม่',
|
Restart: 'ดำเนินการใหม่',
|
||||||
receive: {
|
receive: {
|
||||||
Canceled: 'ยกเลิก',
|
Canceled: 'ยกเลิก',
|
||||||
},
|
},
|
||||||
|
|
@ -1083,6 +1099,7 @@ export default {
|
||||||
flowTemplateNotFound: 'ไม่พบขั้นตอนการทำงาน',
|
flowTemplateNotFound: 'ไม่พบขั้นตอนการทำงาน',
|
||||||
taskOrderNotFound: 'ไม่พบใบสั่งงาน',
|
taskOrderNotFound: 'ไม่พบใบสั่งงาน',
|
||||||
quotationNotFound: 'ไม่พบใบเสนอราคา',
|
quotationNotFound: 'ไม่พบใบเสนอราคา',
|
||||||
|
sameNameExists: 'ชื่อนี้ถูกใช้ไปแล้ว',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -577,7 +577,7 @@ function employeeConfirmUnsave(close = true) {
|
||||||
color: 'warning',
|
color: 'warning',
|
||||||
icon: 'mdi-alert',
|
icon: 'mdi-alert',
|
||||||
title: t('form.warning.title'),
|
title: t('form.warning.title'),
|
||||||
actionText: t('ok'),
|
actionText: t('general.ok'),
|
||||||
persistent: true,
|
persistent: true,
|
||||||
message: t('form.warning.unsave'),
|
message: t('form.warning.unsave'),
|
||||||
action: () => {
|
action: () => {
|
||||||
|
|
@ -604,7 +604,7 @@ function customerConfirmUnsave(close = true) {
|
||||||
color: 'warning',
|
color: 'warning',
|
||||||
icon: 'mdi-alert',
|
icon: 'mdi-alert',
|
||||||
title: t('form.warning.title'),
|
title: t('form.warning.title'),
|
||||||
actionText: t('ok'),
|
actionText: t('general.ok'),
|
||||||
persistent: true,
|
persistent: true,
|
||||||
message: t('form.warning.unsave'),
|
message: t('form.warning.unsave'),
|
||||||
|
|
||||||
|
|
@ -2196,7 +2196,7 @@ const emptyCreateDialog = ref(false);
|
||||||
color: 'warning',
|
color: 'warning',
|
||||||
icon: 'mdi-alert',
|
icon: 'mdi-alert',
|
||||||
title: t('dialog.title.incompleteDataEntry'),
|
title: t('dialog.title.incompleteDataEntry'),
|
||||||
actionText: t('ok'),
|
actionText: t('general.ok'),
|
||||||
persistent: true,
|
persistent: true,
|
||||||
message: t('dialog.message.incompleteDataEntry', {
|
message: t('dialog.message.incompleteDataEntry', {
|
||||||
tap: `${tapIsUndefined.map((v: string) => t(`customerBranch.tab.${v}`)).join(', ')}`,
|
tap: `${tapIsUndefined.map((v: string) => t(`customerBranch.tab.${v}`)).join(', ')}`,
|
||||||
|
|
@ -2419,26 +2419,26 @@ const emptyCreateDialog = ref(false);
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name: 'personalInfo',
|
name: 'personalInfo',
|
||||||
label: 'customerEmployee.form.group.personalInfo',
|
label: $t('customerEmployee.form.group.personalInfo'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'passport',
|
name: 'passport',
|
||||||
label: 'customerEmployee.fileType.passport',
|
label: $t('customerEmployee.fileType.passport'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'visa',
|
name: 'visa',
|
||||||
label: 'customerEmployee.form.group.visa',
|
label: $t('customerEmployee.form.group.visa'),
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'healthCheck',
|
name: 'healthCheck',
|
||||||
label: 'customerEmployee.form.group.healthCheck',
|
label: $t('customerEmployee.form.group.healthCheck'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'workHistory',
|
name: 'workHistory',
|
||||||
label: 'customerEmployee.form.group.workHistory',
|
label: $t('customerEmployee.form.group.workHistory'),
|
||||||
},
|
},
|
||||||
{ name: 'other', label: 'customerEmployee.form.group.other' },
|
{ name: 'other', label: $t('customerEmployee.form.group.other') },
|
||||||
].filter((v) => {
|
].filter((v) => {
|
||||||
if (!employeeFormState.statusSavePersonal) {
|
if (!employeeFormState.statusSavePersonal) {
|
||||||
return v.name === 'personalInfo';
|
return v.name === 'personalInfo';
|
||||||
|
|
@ -4088,7 +4088,7 @@ const emptyCreateDialog = ref(false);
|
||||||
color: 'warning',
|
color: 'warning',
|
||||||
icon: 'mdi-alert',
|
icon: 'mdi-alert',
|
||||||
title: t('dialog.title.incompleteDataEntry'),
|
title: t('dialog.title.incompleteDataEntry'),
|
||||||
actionText: t('ok'),
|
actionText: t('general.ok'),
|
||||||
persistent: true,
|
persistent: true,
|
||||||
message: t('dialog.message.incompleteDataEntry', {
|
message: t('dialog.message.incompleteDataEntry', {
|
||||||
tap: `${tapIsUndefined.map((v: string) => t(`customerBranch.tab.${v}`)).join(', ')}`,
|
tap: `${tapIsUndefined.map((v: string) => t(`customerBranch.tab.${v}`)).join(', ')}`,
|
||||||
|
|
|
||||||
|
|
@ -548,7 +548,7 @@ watch([() => pageState.inputSearch, workflowPageSize], fetchWorkflowList);
|
||||||
<!-- {{ (currentPage - 1) * pageSize + props.rowIndex + 1 }} -->
|
<!-- {{ (currentPage - 1) * pageSize + props.rowIndex + 1 }} -->
|
||||||
</q-td>
|
</q-td>
|
||||||
<q-td v-if="fieldSelected.includes('name')">
|
<q-td v-if="fieldSelected.includes('name')">
|
||||||
<section class="row items-center">
|
<section class="row items-center no-wrap">
|
||||||
<q-avatar
|
<q-avatar
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
size="md"
|
size="md"
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ watch(
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<fieldset class="rounded" style="border: 1px solid var(--gray-4)">
|
<fieldset class="rounded" style="border: 1px solid var(--gray-4)">
|
||||||
<legend>ช่องทางที่ {{ index + 1 }}</legend>
|
<legend>{{ $t('quotation.channelsThat') }} {{ index + 1 }}</legend>
|
||||||
|
|
||||||
<div class="border-5 full-width row" style="gap: var(--size-4)">
|
<div class="border-5 full-width row" style="gap: var(--size-4)">
|
||||||
<div class="column q-pa-sm" style="width: fit-content">
|
<div class="column q-pa-sm" style="width: fit-content">
|
||||||
|
|
@ -56,7 +56,7 @@ watch(
|
||||||
<div class="column col" style="gap: var(--size-3)">
|
<div class="column col" style="gap: var(--size-3)">
|
||||||
<div class="row" style="justify-content: space-between">
|
<div class="row" style="justify-content: space-between">
|
||||||
<div class="text-with-label">
|
<div class="text-with-label">
|
||||||
<div>เลขบัญชีธนาคาร</div>
|
<div>{{ $t('quotation.bankAccountNumber') }}</div>
|
||||||
<div class="row items-start">
|
<div class="row items-start">
|
||||||
<img
|
<img
|
||||||
width="25px"
|
width="25px"
|
||||||
|
|
@ -68,17 +68,17 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-with-label">
|
<div class="text-with-label">
|
||||||
<div>เลขบัญชีธนาคาร</div>
|
<div>{{ $t('quotation.bankAccountNumber') }}</div>
|
||||||
<div>{{ bankBook.accountNumber }}</div>
|
<div>{{ bankBook.accountNumber }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-with-label">
|
<div class="text-with-label">
|
||||||
<div>ชื่อบัญชี</div>
|
<div>{{ $t('quotation.bankAccountName') }}</div>
|
||||||
<div>{{ bankBook.accountName }}</div>
|
<div>{{ bankBook.accountName }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="text-with-label">
|
<div class="text-with-label">
|
||||||
<div>สาขา</div>
|
<div>{{ $t('customerEmployee.branch') }}</div>
|
||||||
<div>{{ bankBook.bankBranch }}</div>
|
<div>{{ bankBook.bankBranch }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ defineProps<{
|
||||||
<template>
|
<template>
|
||||||
<div class="footer-container">
|
<div class="footer-container">
|
||||||
<div class="footer-top">
|
<div class="footer-top">
|
||||||
<div>ในนาม {{ data?.name || '-' }}</div>
|
<div>{{ $t('quotation.inTheNameOf') }} {{ data?.name || '-' }}</div>
|
||||||
<div>ในนาม {{ data?.company || '-' }}</div>
|
<div>{{ $t('quotation.inTheNameOf') }} {{ data?.company || '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<img src="/images/jws-stamp.png" alt="${0}" />
|
<img src="/images/jws-stamp.png" alt="${0}" />
|
||||||
|
|
@ -24,21 +24,21 @@ defineProps<{
|
||||||
<section>
|
<section>
|
||||||
<div>
|
<div>
|
||||||
<span class="data-placeholder"></span>
|
<span class="data-placeholder"></span>
|
||||||
<span>ผู้สั่งซื้อสินค้า</span>
|
<span>{{ $t('quotation.productOrderer') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="data-placeholder"></span>
|
<span class="data-placeholder"></span>
|
||||||
<span>วันที่</span>
|
<span>{{ $t('quotation.date') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<div>
|
<div>
|
||||||
<span class="data-placeholder"></span>
|
<span class="data-placeholder"></span>
|
||||||
<span>ผู้อนุมัติ</span>
|
<span>{{ $t('quotation.approver') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="data-placeholder"></span>
|
<span class="data-placeholder"></span>
|
||||||
<span>วันที่</span>
|
<span>{{ $t('quotation.date') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -442,7 +442,9 @@ function print() {
|
||||||
class="row text-right border-5 items-center"
|
class="row text-right border-5 items-center"
|
||||||
style="width: 40%; background: var(--main); padding: 8px"
|
style="width: 40%; background: var(--main); padding: 8px"
|
||||||
>
|
>
|
||||||
<span style="color: white; font-weight: 600">ยอดรวมสุทธิ</span>
|
<span style="color: white; font-weight: 600">
|
||||||
|
{{ $t('quotation.totalPrice') }}
|
||||||
|
</span>
|
||||||
<span
|
<span
|
||||||
class="border-5"
|
class="border-5"
|
||||||
style="
|
style="
|
||||||
|
|
@ -480,7 +482,7 @@ function print() {
|
||||||
border-bottom: 2px solid var(--main);
|
border-bottom: 2px solid var(--main);
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
หมายเหตุ
|
{{ $t('general.remark') }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
@ -528,7 +530,7 @@ function print() {
|
||||||
border-bottom: 2px solid var(--main);
|
border-bottom: 2px solid var(--main);
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
ช่องทางซำระเงิน
|
{{ $t('quotation.paymentChannels') }}
|
||||||
</span>
|
</span>
|
||||||
<article style="height: 5.8in">
|
<article style="height: 5.8in">
|
||||||
<BankComponents
|
<BankComponents
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ function titleMode(mode: View): string {
|
||||||
<span>{{ branch.webUrl }}</span>
|
<span>{{ branch.webUrl }}</span>
|
||||||
</article>
|
</article>
|
||||||
<article>
|
<article>
|
||||||
<b>ลูกค้า</b>
|
<b>{{ $t('quotation.customer') }}</b>
|
||||||
<span>
|
<span>
|
||||||
{{
|
{{
|
||||||
formatAddress({
|
formatAddress({
|
||||||
|
|
@ -111,29 +111,29 @@ function titleMode(mode: View): string {
|
||||||
<div>{{ details.code }}</div>
|
<div>{{ details.code }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div>วันที่ใบเสนอราคา</div>
|
<div>{{ $t('quotation.quotationDate') }}</div>
|
||||||
<div>{{ dateFormat(details.createdAt, true, false, true) }}</div>
|
<div>{{ dateFormat(details.createdAt, true, false, true) }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div>ผู้ขาย</div>
|
<div>{{ $t('quotation.seller') }}</div>
|
||||||
<div>{{ details.createdBy }}</div>
|
<div>{{ details.createdBy }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div>เงื่อนไขการชำระ</div>
|
<div>{{ $t('quotation.paymentCondition') }}</div>
|
||||||
<div>
|
<div>
|
||||||
{{ $t(`quotation.type.${details.payCondition}`) }}
|
{{ $t(`quotation.type.${details.payCondition}`) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div>ชื่องาน</div>
|
<div>{{ $t('quotation.workName') }}</div>
|
||||||
<div>{{ details.workName }}</div>
|
<div>{{ details.workName }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div>ผู้ติดต่อ</div>
|
<div>{{ $t('quotation.contactName') }}</div>
|
||||||
<div>{{ details.contactName }}</div>
|
<div>{{ details.contactName }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div>วันครบกำหนดชำระ</div>
|
<div>{{ $t('quotation.receiptDialog.paymentDueDate') }}</div>
|
||||||
<div>{{ dateFormat(details.dueDate, true, false, true) }}</div>
|
<div>{{ dateFormat(details.dueDate, true, false, true) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ import FloatingActionButton from 'src/components/FloatingActionButton.vue';
|
||||||
import CreateButton from 'src/components/AddButton.vue';
|
import CreateButton from 'src/components/AddButton.vue';
|
||||||
import NoData from 'src/components/NoData.vue';
|
import NoData from 'src/components/NoData.vue';
|
||||||
import AgenciesDialog from './AgenciesDialog.vue';
|
import AgenciesDialog from './AgenciesDialog.vue';
|
||||||
import { computed } from 'vue';
|
|
||||||
import { watch } from 'vue';
|
import { watch } from 'vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
@ -28,7 +27,6 @@ const institutionStore = useInstitution();
|
||||||
|
|
||||||
const { data, page, pageMax, pageSize } = storeToRefs(institutionStore);
|
const { data, page, pageMax, pageSize } = storeToRefs(institutionStore);
|
||||||
|
|
||||||
const statusFilter = ref<'all' | 'statusACTIVE' | 'statusINACTIVE'>('all');
|
|
||||||
const fieldSelected = ref<('orderNumber' | 'name' | 'address')[]>([
|
const fieldSelected = ref<('orderNumber' | 'name' | 'address')[]>([
|
||||||
'orderNumber',
|
'orderNumber',
|
||||||
'name',
|
'name',
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,12 @@ import DutyExpansion from './DutyExpansion.vue';
|
||||||
import MessengerExpansion from './MessengerExpansion.vue';
|
import MessengerExpansion from './MessengerExpansion.vue';
|
||||||
|
|
||||||
// NOTE: Store
|
// NOTE: Store
|
||||||
import { baseUrl, dialog } from 'src/stores/utils';
|
import {
|
||||||
|
baseUrl,
|
||||||
|
dialog,
|
||||||
|
getEmployeeName,
|
||||||
|
getCustomerName,
|
||||||
|
} from 'src/stores/utils';
|
||||||
import { dateFormatJS } from 'src/utils/datetime';
|
import { dateFormatJS } from 'src/utils/datetime';
|
||||||
import { useRequestList } from 'src/stores/request-list';
|
import { useRequestList } from 'src/stores/request-list';
|
||||||
import {
|
import {
|
||||||
|
|
@ -79,47 +84,6 @@ async function fetchRequestWorkList(opts: { requestDataId: string }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCustomerName(
|
|
||||||
record: RequestData,
|
|
||||||
opts?: {
|
|
||||||
locale?: string;
|
|
||||||
noCode?: boolean;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const customer = record.quotation.customerBranch;
|
|
||||||
|
|
||||||
return (
|
|
||||||
{
|
|
||||||
['CORP']: {
|
|
||||||
[Lang.English]: customer.registerNameEN,
|
|
||||||
[Lang.Thai]: customer.registerName,
|
|
||||||
}[opts?.locale || 'eng'],
|
|
||||||
['PERS']:
|
|
||||||
{
|
|
||||||
[Lang.English]: `${optionStore.mapOption(customer.namePrefix)} ${customer.firstNameEN} ${customer.lastNameEN}`,
|
|
||||||
[Lang.Thai]: `${optionStore.mapOption(customer.namePrefix)} ${customer.firstName} ${customer.lastName}`,
|
|
||||||
}[opts?.locale || Lang.English] || '-',
|
|
||||||
}[customer.customer.customerType] +
|
|
||||||
(opts?.noCode ? '' : ' ' + `(${customer.code})`)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getEmployeeName(
|
|
||||||
record: RequestData,
|
|
||||||
opts?: {
|
|
||||||
locale?: string;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const employee = record.employee;
|
|
||||||
|
|
||||||
return (
|
|
||||||
{
|
|
||||||
[Lang.English]: `${optionStore.mapOption(employee.namePrefix)} ${employee.firstNameEN} ${employee.lastNameEN}`,
|
|
||||||
[Lang.Thai]: `${optionStore.mapOption(employee.namePrefix)} ${employee.firstName} ${employee.lastName}`,
|
|
||||||
}[opts?.locale || Lang.English] || '-'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getData() {
|
async function getData() {
|
||||||
const current = route.params['requestListId'];
|
const current = route.params['requestListId'];
|
||||||
|
|
||||||
|
|
@ -611,8 +575,10 @@ function goToQuotation(
|
||||||
icon="mdi-account-settings-outline"
|
icon="mdi-account-settings-outline"
|
||||||
:label="$t('customer.employer')"
|
:label="$t('customer.employer')"
|
||||||
:value="
|
:value="
|
||||||
getCustomerName(data, { locale: locale, noCode: true }) ||
|
getCustomerName(data.quotation.customerBranch, {
|
||||||
'-'
|
locale: locale,
|
||||||
|
noCode: true,
|
||||||
|
}) || '-'
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<DataDisplay
|
<DataDisplay
|
||||||
|
|
@ -620,7 +586,9 @@ function goToQuotation(
|
||||||
icon="mdi-account-settings-outline"
|
icon="mdi-account-settings-outline"
|
||||||
:label="$t('customer.employee')"
|
:label="$t('customer.employee')"
|
||||||
:value="
|
:value="
|
||||||
getEmployeeName(data, { locale: $i18n.locale }) || '-'
|
getEmployeeName(data.employee, {
|
||||||
|
locale: $i18n.locale,
|
||||||
|
}) || '-'
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<DataDisplay
|
<DataDisplay
|
||||||
|
|
@ -631,6 +599,40 @@ function goToQuotation(
|
||||||
/>
|
/>
|
||||||
<div v-if="$q.screen.gt.sm" class="col"></div>
|
<div v-if="$q.screen.gt.sm" class="col"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<FormGroupHead class="col-12">
|
||||||
|
{{ $t('general.contactName') }}
|
||||||
|
</FormGroupHead>
|
||||||
|
<div
|
||||||
|
class="col-12 q-pa-sm"
|
||||||
|
:class="{
|
||||||
|
row: $q.screen.gt.sm,
|
||||||
|
'column q-gutter-y-sm': $q.screen.lt.md,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<DataDisplay
|
||||||
|
class="col"
|
||||||
|
icon="mdi-account-settings-outline"
|
||||||
|
:label="$t('quotation.actor')"
|
||||||
|
:value="
|
||||||
|
getEmployeeName(data.quotation?.createdBy, {
|
||||||
|
locale: $i18n.locale,
|
||||||
|
}) || '-'
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<DataDisplay
|
||||||
|
class="col"
|
||||||
|
icon="mdi-account-settings-outline"
|
||||||
|
:label="$t('quotation.contactName')"
|
||||||
|
:value="data.quotation?.contactName || '-'"
|
||||||
|
/>
|
||||||
|
<DataDisplay
|
||||||
|
class="col"
|
||||||
|
icon="mdi-telephone-outline"
|
||||||
|
:label="$t('general.telephone')"
|
||||||
|
:value="data.quotation.contactTel || '-'"
|
||||||
|
/>
|
||||||
|
<div v-if="$q.screen.gt.sm" class="col"></div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</transition>
|
</transition>
|
||||||
</article>
|
</article>
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,7 @@ const currStatus = computed(() =>
|
||||||
statusList.find((v) => v.value === props.status),
|
statusList.find((v) => v.value === props.status),
|
||||||
);
|
);
|
||||||
|
|
||||||
function hideIcon() {
|
function inactiveCheck() {
|
||||||
if (props.noAction) return props.noAction;
|
|
||||||
if (props.type === 'order') {
|
if (props.type === 'order') {
|
||||||
return (
|
return (
|
||||||
currStatus.value?.value === TaskStatus.InProgress ||
|
currStatus.value?.value === TaskStatus.InProgress ||
|
||||||
|
|
@ -81,7 +80,8 @@ function hideIcon() {
|
||||||
"
|
"
|
||||||
class="text-capitalize text-weight-regular product-status rounded"
|
class="text-capitalize text-weight-regular product-status rounded"
|
||||||
:class="{
|
:class="{
|
||||||
'hide-icon q-pr-md': hideIcon(),
|
'inactive hide-icon q-pr-md': inactiveCheck(),
|
||||||
|
'hide-icon q-pr-md': noAction,
|
||||||
warning:
|
warning:
|
||||||
currStatus?.value === TaskStatus.Pending ||
|
currStatus?.value === TaskStatus.Pending ||
|
||||||
currStatus?.value === TaskStatus.InProgress,
|
currStatus?.value === TaskStatus.InProgress,
|
||||||
|
|
@ -95,7 +95,9 @@ function hideIcon() {
|
||||||
currStatus?.value === TaskStatus.Canceled ||
|
currStatus?.value === TaskStatus.Canceled ||
|
||||||
currStatus?.value === TaskStatus.Restart,
|
currStatus?.value === TaskStatus.Restart,
|
||||||
'pointer-events-none': {
|
'pointer-events-none': {
|
||||||
order: !['Success', 'Failed', 'Validate'].includes(status || ''),
|
order: !['Success', 'Failed', 'Validate', 'Redo'].includes(
|
||||||
|
status || '',
|
||||||
|
),
|
||||||
receive: status !== TaskStatus.InProgress,
|
receive: status !== TaskStatus.InProgress,
|
||||||
}[type ?? 'order'],
|
}[type ?? 'order'],
|
||||||
}"
|
}"
|
||||||
|
|
@ -171,6 +173,11 @@ function hideIcon() {
|
||||||
&.negative {
|
&.negative {
|
||||||
--_color: var(--negative-bg);
|
--_color: var(--negative-bg);
|
||||||
}
|
}
|
||||||
|
&.inactive {
|
||||||
|
--_color: var(--stone-7-hsl);
|
||||||
|
opacity: 0.8;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.pointer-events-none {
|
.pointer-events-none {
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ export const taskStatusOrderToggle = [
|
||||||
{
|
{
|
||||||
value: TaskStatus.InProgress,
|
value: TaskStatus.InProgress,
|
||||||
icon: 'mdi-file-move-outline',
|
icon: 'mdi-file-move-outline',
|
||||||
color: 'positive',
|
color: 'warning',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: TaskStatus.Complete,
|
value: TaskStatus.Complete,
|
||||||
|
|
|
||||||
|
|
@ -380,7 +380,9 @@ function print() {
|
||||||
class="row text-right border-5 items-center"
|
class="row text-right border-5 items-center"
|
||||||
style="width: 40%; background: var(--main); padding: 8px"
|
style="width: 40%; background: var(--main); padding: 8px"
|
||||||
>
|
>
|
||||||
<span style="color: white; font-weight: 600">ยอดรวมสุทธิ</span>
|
<span style="color: white; font-weight: 600">
|
||||||
|
{{ $t('quotation.totalPrice') }}
|
||||||
|
</span>
|
||||||
<span
|
<span
|
||||||
class="border-5"
|
class="border-5"
|
||||||
style="
|
style="
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ defineProps<{
|
||||||
<template>
|
<template>
|
||||||
<div class="footer-container">
|
<div class="footer-container">
|
||||||
<div class="footer-top">
|
<div class="footer-top">
|
||||||
<div>ในนาม {{ data?.name || '-' }}</div>
|
<div>{{ $t('taskOrder.inTheNameOf') }} {{ data?.name || '-' }}</div>
|
||||||
<div>ในนาม {{ data?.company || '-' }}</div>
|
<div>{{ $t('taskOrder.inTheNameOf') }} {{ data?.company || '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<img src="/images/jws-stamp.png" alt="${0}" />
|
<img src="/images/jws-stamp.png" alt="${0}" />
|
||||||
|
|
@ -24,21 +24,21 @@ defineProps<{
|
||||||
<section>
|
<section>
|
||||||
<div>
|
<div>
|
||||||
<span class="data-placeholder"></span>
|
<span class="data-placeholder"></span>
|
||||||
<span>ผู้สั่งซื้อสินค้า</span>
|
<span>{{ $t('taskOrder.productOrderer') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="data-placeholder"></span>
|
<span class="data-placeholder"></span>
|
||||||
<span>วันที่</span>
|
<span>{{ $t('taskOrder.date') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<div>
|
<div>
|
||||||
<span class="data-placeholder"></span>
|
<span class="data-placeholder"></span>
|
||||||
<span>ผู้อนุมัติ</span>
|
<span>{{ $t('taskOrder.approver') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="data-placeholder"></span>
|
<span class="data-placeholder"></span>
|
||||||
<span>วันที่</span>
|
<span>{{ $t('taskOrder.date') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -101,11 +101,11 @@ defineProps<{
|
||||||
<div>{{ details.code }}</div>
|
<div>{{ details.code }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div>ชื่องาน</div>
|
<div>{{ $t('taskOrder.workName') }}</div>
|
||||||
<div>{{ details.name }}</div>
|
<div>{{ details.name }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div>ผู้ติดต่อ</div>
|
<div>{{ $t('taskOrder.contacts') }}</div>
|
||||||
<div>{{ details.contactName }}</div>
|
<div>{{ details.contactName }}</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ const contactTel = defineModel<string>('contactTel');
|
||||||
class="col-md-4 col-12"
|
class="col-md-4 col-12"
|
||||||
:label="`${$t('taskOrder.issueBranch')}${$i18n.locale === 'tha' ? $t('taskOrder.title') : ''}`"
|
:label="`${$t('taskOrder.issueBranch')}${$i18n.locale === 'tha' ? $t('taskOrder.title') : ''}`"
|
||||||
v-model:value="registeredBranchId"
|
v-model:value="registeredBranchId"
|
||||||
|
auto-select-on-single
|
||||||
/>
|
/>
|
||||||
<SelectInstitution
|
<SelectInstitution
|
||||||
:readonly
|
:readonly
|
||||||
|
|
@ -51,6 +52,7 @@ const contactTel = defineModel<string>('contactTel');
|
||||||
v-model:value="institutionId"
|
v-model:value="institutionId"
|
||||||
:disabled="taskListGroup"
|
:disabled="taskListGroup"
|
||||||
:params="{ payload: { group: institutionGroup } }"
|
:params="{ payload: { group: institutionGroup } }"
|
||||||
|
auto-select-on-single
|
||||||
/>
|
/>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
:label="$t('taskOrder.issueDate')"
|
:label="$t('taskOrder.issueDate')"
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,6 @@ import { SaveButton, MainButton, EditButton } from 'src/components/button';
|
||||||
import FormGroupHead from 'src/pages/08_request-list/FormGroupHead.vue';
|
import FormGroupHead from 'src/pages/08_request-list/FormGroupHead.vue';
|
||||||
import FailRemarkDialog from '../receive_view/FailRemarkDialog.vue';
|
import FailRemarkDialog from '../receive_view/FailRemarkDialog.vue';
|
||||||
|
|
||||||
import { taskStatusOpts } from '../constants';
|
|
||||||
|
|
||||||
import SelectReadyRequestWork from '../SelectReadyRequestWork.vue';
|
import SelectReadyRequestWork from '../SelectReadyRequestWork.vue';
|
||||||
import { dialogWarningClose } from 'stores/utils';
|
import { dialogWarningClose } from 'stores/utils';
|
||||||
import useOptionStore from 'src/stores/options';
|
import useOptionStore from 'src/stores/options';
|
||||||
|
|
@ -37,15 +35,12 @@ import {
|
||||||
UserTaskStatus,
|
UserTaskStatus,
|
||||||
} from 'src/stores/task-order/types';
|
} from 'src/stores/task-order/types';
|
||||||
import { RequestWork } from 'src/stores/request-list';
|
import { RequestWork } from 'src/stores/request-list';
|
||||||
import { precisionRound } from 'src/utils/arithmetic';
|
|
||||||
import { getUserId } from 'src/services/keycloak';
|
|
||||||
|
|
||||||
const taskOrderFormStore = useTaskOrderForm();
|
const taskOrderFormStore = useTaskOrderForm();
|
||||||
const taskOrderStore = useTaskOrderStore();
|
const taskOrderStore = useTaskOrderStore();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const configStore = useConfigStore();
|
const configStore = useConfigStore();
|
||||||
const optionStore = useOptionStore();
|
|
||||||
const { data: config } = storeToRefs(configStore);
|
const { data: config } = storeToRefs(configStore);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
|
@ -59,6 +54,7 @@ const fileData = ref<
|
||||||
loaded: number;
|
loaded: number;
|
||||||
total: number;
|
total: number;
|
||||||
url?: string;
|
url?: string;
|
||||||
|
placeholder?: boolean;
|
||||||
}[]
|
}[]
|
||||||
>([]);
|
>([]);
|
||||||
|
|
||||||
|
|
@ -397,6 +393,11 @@ async function submitForm() {
|
||||||
});
|
});
|
||||||
if (res && currentFormData.value.id) {
|
if (res && currentFormData.value.id) {
|
||||||
await taskOrderFormStore.assignFormData(currentFormData.value.id);
|
await taskOrderFormStore.assignFormData(currentFormData.value.id);
|
||||||
|
|
||||||
|
if (fileList.value) {
|
||||||
|
await uploadFile(currentFormData.value.id, fileList.value);
|
||||||
|
}
|
||||||
|
|
||||||
router.push({
|
router.push({
|
||||||
name: 'TaskOrderView',
|
name: 'TaskOrderView',
|
||||||
params: { id: currentFormData.value.id },
|
params: { id: currentFormData.value.id },
|
||||||
|
|
@ -445,25 +446,29 @@ async function getFileList(taskId: string) {
|
||||||
if (fileList)
|
if (fileList)
|
||||||
fileData.value = await Promise.all(
|
fileData.value = await Promise.all(
|
||||||
fileList.map(async (v) => {
|
fileList.map(async (v) => {
|
||||||
const rse = await taskOrderStore.headAttachment({
|
const res = await taskOrderStore.headAttachment({
|
||||||
parentId: taskId,
|
parentId: taskId,
|
||||||
fileId: v,
|
fileId: v,
|
||||||
});
|
});
|
||||||
|
|
||||||
let contentLength = 0;
|
let contentLength = 0;
|
||||||
if (rse) contentLength = Number(rse['content-length']);
|
if (res) contentLength = Number(res['content-length']);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: v,
|
name: v,
|
||||||
progress: 1,
|
progress: 1,
|
||||||
loaded: contentLength,
|
loaded: contentLength,
|
||||||
total: contentLength,
|
total: contentLength,
|
||||||
url: `/task/${taskId}/attachment/${v}`,
|
url: `/task-order/${taskId}/attachment/${v}`,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fileToUrl(file: File) {
|
||||||
|
return URL.createObjectURL(file);
|
||||||
|
}
|
||||||
|
|
||||||
async function remove(taskId: string, n: string) {
|
async function remove(taskId: string, n: string) {
|
||||||
dialogWarningClose(t, {
|
dialogWarningClose(t, {
|
||||||
message: t('dialog.message.confirmDelete'),
|
message: t('dialog.message.confirmDelete'),
|
||||||
|
|
@ -508,8 +513,18 @@ async function uploadFile(taskId: string, list: FileList) {
|
||||||
);
|
);
|
||||||
fileData?.value.push(data);
|
fileData?.value.push(data);
|
||||||
}
|
}
|
||||||
|
fileList.value = undefined;
|
||||||
|
|
||||||
return await Promise.all(promises);
|
const beforeUnloadHandler = (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', beforeUnloadHandler);
|
||||||
|
|
||||||
|
return await Promise.all(promises).then((v) => {
|
||||||
|
window.removeEventListener('beforeunload', beforeUnloadHandler);
|
||||||
|
return v;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function completeValidate() {
|
async function completeValidate() {
|
||||||
|
|
@ -642,6 +657,33 @@ function handleChangeStatus(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sortList(
|
||||||
|
list: (RequestWork & {
|
||||||
|
_template?: {
|
||||||
|
id: string;
|
||||||
|
templateName: string;
|
||||||
|
templateStepName: string;
|
||||||
|
step: number;
|
||||||
|
responsibleInstitution: (string | { group: string })[];
|
||||||
|
} | null;
|
||||||
|
taskStatus: TaskStatus;
|
||||||
|
})[],
|
||||||
|
) {
|
||||||
|
const prioritizedStatuses = new Set([
|
||||||
|
TaskStatus.InProgress,
|
||||||
|
TaskStatus.Redo,
|
||||||
|
TaskStatus.Success,
|
||||||
|
TaskStatus.Complete,
|
||||||
|
TaskStatus.Canceled,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return list.sort((a, b) => {
|
||||||
|
const aPriority = prioritizedStatuses.has(a.taskStatus) ? 1 : 0;
|
||||||
|
const bPriority = prioritizedStatuses.has(b.taskStatus) ? 1 : 0;
|
||||||
|
return aPriority - bPriority;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
watch([currentFormData.value.taskStatus], () => {
|
watch([currentFormData.value.taskStatus], () => {
|
||||||
fetchStatus();
|
fetchStatus();
|
||||||
});
|
});
|
||||||
|
|
@ -821,9 +863,13 @@ watch([currentFormData.value.taskStatus], () => {
|
||||||
v-model:file-data="fileData"
|
v-model:file-data="fileData"
|
||||||
:transform-url="
|
:transform-url="
|
||||||
async (url: string) => {
|
async (url: string) => {
|
||||||
|
if (state.mode === 'create') {
|
||||||
|
return url;
|
||||||
|
} else {
|
||||||
const result = await api.get<string>(url);
|
const result = await api.get<string>(url);
|
||||||
return result.data;
|
return result.data;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
"
|
"
|
||||||
@fetch-file-list="
|
@fetch-file-list="
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -833,9 +879,21 @@ watch([currentFormData.value.taskStatus], () => {
|
||||||
"
|
"
|
||||||
@upload="
|
@upload="
|
||||||
async (f) => {
|
async (f) => {
|
||||||
if (!currentFormData.id) return;
|
|
||||||
|
|
||||||
fileList = f;
|
fileList = f;
|
||||||
|
fileData = [];
|
||||||
|
|
||||||
|
Array.from(f).forEach((el) => {
|
||||||
|
fileData.push({
|
||||||
|
name: el.name,
|
||||||
|
progress: 1,
|
||||||
|
loaded: 0,
|
||||||
|
total: el.size,
|
||||||
|
placeholder: true,
|
||||||
|
url: fileToUrl(el),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!currentFormData.id) return;
|
||||||
|
|
||||||
await uploadFile(currentFormData.id, f);
|
await uploadFile(currentFormData.id, f);
|
||||||
}
|
}
|
||||||
|
|
@ -973,7 +1031,7 @@ watch([currentFormData.value.taskStatus], () => {
|
||||||
(l) => l.userId === v.responsibleUser.id,
|
(l) => l.userId === v.responsibleUser.id,
|
||||||
)?.userTaskStatus === UserTaskStatus.Submit
|
)?.userTaskStatus === UserTaskStatus.Submit
|
||||||
"
|
"
|
||||||
:rows="list"
|
:rows="sortList(list)"
|
||||||
@change-all-status="
|
@change-all-status="
|
||||||
(v) =>
|
(v) =>
|
||||||
handleChangeStatus(
|
handleChangeStatus(
|
||||||
|
|
@ -997,7 +1055,6 @@ watch([currentFormData.value.taskStatus], () => {
|
||||||
fullTaskOrder?.userTask.find(
|
fullTaskOrder?.userTask.find(
|
||||||
(l) => l.userId === v.responsibleUser.id,
|
(l) => l.userId === v.responsibleUser.id,
|
||||||
)?.userTaskStatus;
|
)?.userTaskStatus;
|
||||||
console.log(_userStatus);
|
|
||||||
return (
|
return (
|
||||||
_userStatus !== UserTaskStatus.Submit &&
|
_userStatus !== UserTaskStatus.Submit &&
|
||||||
_userStatus !== UserTaskStatus.Restart
|
_userStatus !== UserTaskStatus.Restart
|
||||||
|
|
|
||||||
|
|
@ -313,6 +313,35 @@ function taskStatusCount(index: number, id: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sortList(
|
||||||
|
list: (RequestWork & {
|
||||||
|
_template?: {
|
||||||
|
id: string;
|
||||||
|
templateName: string;
|
||||||
|
templateStepName: string;
|
||||||
|
step: number;
|
||||||
|
} | null;
|
||||||
|
taskStatus?: TaskStatus;
|
||||||
|
})[],
|
||||||
|
) {
|
||||||
|
const prioritizedStatuses = new Set([
|
||||||
|
TaskStatus.Failed,
|
||||||
|
TaskStatus.Success,
|
||||||
|
TaskStatus.Complete,
|
||||||
|
TaskStatus.Redo,
|
||||||
|
TaskStatus.Validate,
|
||||||
|
TaskStatus.Canceled,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return list.sort((a, b) => {
|
||||||
|
const aPriority =
|
||||||
|
a.taskStatus && prioritizedStatuses.has(a.taskStatus) ? 1 : 0;
|
||||||
|
const bPriority =
|
||||||
|
b.taskStatus && prioritizedStatuses.has(b.taskStatus) ? 1 : 0;
|
||||||
|
return aPriority - bPriority;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
initTheme();
|
initTheme();
|
||||||
initLang();
|
initLang();
|
||||||
|
|
@ -607,7 +636,7 @@ watch([currentFormData.value.taskStatus], () => {
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
step-on
|
step-on
|
||||||
:rows="list"
|
:rows="sortList(list)"
|
||||||
@change-all-status="(v) => handleChangeStatus(v, i)"
|
@change-all-status="(v) => handleChangeStatus(v, i)"
|
||||||
v-model:selected-employee="selectedEmployee[i]"
|
v-model:selected-employee="selectedEmployee[i]"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,8 @@ async function fetchList(opts?: { rotateFlowId?: boolean }) {
|
||||||
: pageState.statusFilter === PaymentDataStatus.Wait
|
: pageState.statusFilter === PaymentDataStatus.Wait
|
||||||
? false
|
? false
|
||||||
: undefined,
|
: undefined,
|
||||||
|
quotationOnly: true,
|
||||||
|
debitNoteOnly: false,
|
||||||
});
|
});
|
||||||
if (ret) {
|
if (ret) {
|
||||||
data.value = ret.result;
|
data.value = ret.result;
|
||||||
|
|
@ -64,7 +66,10 @@ async function fetchList(opts?: { rotateFlowId?: boolean }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchStats() {
|
async function fetchStats() {
|
||||||
const ret = await invoiceStore.getInvoiceStats();
|
const ret = await invoiceStore.getInvoiceStats({
|
||||||
|
quotationOnly: true,
|
||||||
|
debitNoteOnly: false,
|
||||||
|
});
|
||||||
if (ret) stats.value = ret;
|
if (ret) stats.value = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -490,6 +490,10 @@ async function getFileList(creditNoteId: string, slip?: boolean) {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fileToUrl(file: File) {
|
||||||
|
return URL.createObjectURL(file);
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
initTheme();
|
initTheme();
|
||||||
initLang();
|
initLang();
|
||||||
|
|
@ -653,9 +657,13 @@ onMounted(async () => {
|
||||||
v-model:file-data="attachmentData"
|
v-model:file-data="attachmentData"
|
||||||
:transform-url="
|
:transform-url="
|
||||||
async (url: string) => {
|
async (url: string) => {
|
||||||
|
if (!creditNoteData?.id) {
|
||||||
|
return url;
|
||||||
|
} else {
|
||||||
const result = await api.get<string>(url);
|
const result = await api.get<string>(url);
|
||||||
return result.data;
|
return result.data;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
"
|
"
|
||||||
@fetch-file-list="
|
@fetch-file-list="
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -675,6 +683,7 @@ onMounted(async () => {
|
||||||
loaded: 0,
|
loaded: 0,
|
||||||
total: el.size,
|
total: el.size,
|
||||||
placeholder: true,
|
placeholder: true,
|
||||||
|
url: fileToUrl(el),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -179,13 +179,13 @@ watch(
|
||||||
icon: 'material-symbols-light:receipt-long',
|
icon: 'material-symbols-light:receipt-long',
|
||||||
count: stats[CreditNoteStatus.Pending],
|
count: stats[CreditNoteStatus.Pending],
|
||||||
label: `creditNote.stats.${CreditNoteStatus.Pending}`,
|
label: `creditNote.stats.${CreditNoteStatus.Pending}`,
|
||||||
color: 'blue',
|
color: 'orange',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'mdi-check-decagram-outline',
|
icon: 'mdi-check-decagram-outline',
|
||||||
count: stats[CreditNoteStatus.Success],
|
count: stats[CreditNoteStatus.Success],
|
||||||
label: `creditNote.stats.${CreditNoteStatus.Success}`,
|
label: `creditNote.stats.${CreditNoteStatus.Success}`,
|
||||||
color: 'orange',
|
color: 'blue',
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
:dark="$q.dark.isActive"
|
:dark="$q.dark.isActive"
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,6 @@ export const columns = [
|
||||||
] as const satisfies QTableProps['columns'];
|
] as const satisfies QTableProps['columns'];
|
||||||
|
|
||||||
export const hslaColors: Record<string, string> = {
|
export const hslaColors: Record<string, string> = {
|
||||||
Pending: '--blue-6-hsl',
|
Pending: '--orange-5-hsl',
|
||||||
Success: '--red-6-hsl',
|
Success: '--blue-6-hsl',
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,12 @@ export const useInvoice = defineStore('invoice-store', () => {
|
||||||
[PaymentDataStatus.Wait]: 0,
|
[PaymentDataStatus.Wait]: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getInvoiceStats(params?: { quotationId?: string }) {
|
async function getInvoiceStats(params?: {
|
||||||
|
quotationId?: string;
|
||||||
|
quotationOnly?: boolean;
|
||||||
|
debitNoteId?: string;
|
||||||
|
debitNoteOnly?: boolean;
|
||||||
|
}) {
|
||||||
const res = await api.get<Record<PaymentDataStatus, number>>(
|
const res = await api.get<Record<PaymentDataStatus, number>>(
|
||||||
'/invoice/stats',
|
'/invoice/stats',
|
||||||
{ params },
|
{ params },
|
||||||
|
|
@ -149,8 +154,11 @@ export const useInvoice = defineStore('invoice-store', () => {
|
||||||
page?: number;
|
page?: number;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
query?: string;
|
query?: string;
|
||||||
quotationId?: string;
|
|
||||||
pay?: boolean;
|
pay?: boolean;
|
||||||
|
quotationOnly?: boolean;
|
||||||
|
debitNoteOnly?: boolean;
|
||||||
|
quotationId?: string;
|
||||||
|
debitNoteId?: string;
|
||||||
}) {
|
}) {
|
||||||
const res = await api.get<PaginationResult<Invoice>>('/invoice', {
|
const res = await api.get<PaginationResult<Invoice>>('/invoice', {
|
||||||
params,
|
params,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import useOptionStore from '../options';
|
||||||
import { CustomerBranch } from '../customer/types';
|
import { CustomerBranch } from '../customer/types';
|
||||||
import { CustomerBranchRelation } from '../quotations';
|
import { CustomerBranchRelation } from '../quotations';
|
||||||
import { Employee } from '../employee/types';
|
import { Employee } from '../employee/types';
|
||||||
|
import { CreatedBy } from '../types';
|
||||||
|
|
||||||
export const baseUrl = import.meta.env.VITE_API_BASE_URL;
|
export const baseUrl = import.meta.env.VITE_API_BASE_URL;
|
||||||
|
|
||||||
|
|
@ -510,7 +511,7 @@ export async function getAttachmentHead(api: AxiosInstance, url: string) {
|
||||||
if (res) return res.headers;
|
if (res) return res.headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateDaysUntilExpire(expireDate: Date): number {
|
export function calculateDaysUntilExpire(expireDate: Date | string): number {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
const expire = new Date(expireDate);
|
const expire = new Date(expireDate);
|
||||||
const diffInTime = expire.getTime() - today.getTime();
|
const diffInTime = expire.getTime() - today.getTime();
|
||||||
|
|
@ -596,7 +597,7 @@ export function getCustomerName(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getEmployeeName(
|
export function getEmployeeName(
|
||||||
record: Employee,
|
record: Employee | CreatedBy,
|
||||||
opts?: {
|
opts?: {
|
||||||
locale?: string;
|
locale?: string;
|
||||||
},
|
},
|
||||||
|
|
@ -604,7 +605,7 @@ export function getEmployeeName(
|
||||||
const employee = record;
|
const employee = record;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
['eng']: `${useOptionStore().mapOption(employee.namePrefix)} ${employee.firstNameEN} ${employee.lastNameEN}`,
|
['eng']: `${typeof employee.namePrefix === 'string' ? useOptionStore().mapOption(employee.namePrefix) : ''} ${employee.firstNameEN} ${employee.lastNameEN}`,
|
||||||
['tha']: `${useOptionStore().mapOption(employee.namePrefix)} ${employee.firstName} ${employee.lastName}`,
|
['tha']: `${typeof employee.namePrefix === 'string' ? useOptionStore().mapOption(employee.namePrefix) : ''} ${employee.firstName} ${employee.lastName}`,
|
||||||
}[opts?.locale || 'eng'];
|
}[opts?.locale || 'eng'];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue