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