refactor: restructure

This commit is contained in:
Methapon2001 2024-08-08 09:06:00 +07:00
parent 7a81991c79
commit 11ff03ec50
8 changed files with 16 additions and 9 deletions

View file

@ -0,0 +1,482 @@
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue';
import useCustomerStore from 'stores/customer';
import useFlowStore from 'stores/flow';
import useOptionStore from 'stores/options';
import { Status } from 'stores/types';
import { CustomerBranch, CustomerType } from 'stores/customer/types';
import BranchCardCustomer from 'components/03_customer-management/BranchCardCustomer.vue';
import PaginationComponent from 'components/PaginationComponent.vue';
import NoData from 'components/NoData.vue';
import { QTableProps } from 'quasar';
const flowStore = useFlowStore();
const userCustomer = useCustomerStore();
const { fetchListCustomeBranch } = userCustomer;
const inputSearch = ref<string>('');
const branch = defineModel<CustomerBranch[]>('branch');
const currentCustomerName = defineModel<string>('currentCustomerName');
const modeView = defineModel<boolean>('modeView');
const currentCustomerUrlImage = defineModel<string | null>(
'currentCustomerUrlImage',
);
const currentStatus = ref<Status | 'All'>('All');
const totalBranch = ref(0);
const currentPageBranch = ref<number>(1);
const maxPageBranch = ref<number>(1);
const pageSizeBranch = ref<number>(30);
const prop = withDefaults(
defineProps<{
color?: 'purple' | 'green';
customerId: string;
customerType: CustomerType;
}>(),
{
color: 'green',
},
);
defineEmits<{
(e: 'back'): void;
(e: 'viewDetail', branch: CustomerBranch, index: number): void;
(e: 'dialog'): void;
}>();
onMounted(async () => {
await fetchList();
});
const columns = [
{
name: 'branchLabelName',
align: 'left',
label: 'office',
field: 'name',
sortable: true,
},
{
name: 'branchLabelAddress',
align: 'left',
label: 'address',
field: 'address',
sortable: true,
},
{
name: 'branchLabelTel',
align: 'left',
label: 'formDialogInputTelephone',
field: 'telephoneNo',
},
] satisfies QTableProps['columns'];
const fieldDisplay = ref<
(
| 'branchName'
| 'customerBranchFormTab'
| 'address'
| 'telephone'
| 'businessTypePure'
| 'totalEmployee'
)[]
>([
'branchName',
'customerBranchFormTab',
'address',
'telephone',
'businessTypePure',
'totalEmployee',
]);
const branchFieldSelected = ref<
(
| 'customerBranchFormTab'
| 'branchName'
| 'address'
| 'telephone'
| 'businessTypePure'
| 'totalEmployee'
)[]
>(fieldDisplay.value);
async function fetchList() {
const result = await fetchListCustomeBranch({
customerId: prop.customerId,
query: !!inputSearch.value ? inputSearch.value : undefined,
page: currentPageBranch.value,
pageSize: pageSizeBranch.value,
includeCustomer: true,
status:
currentStatus.value === 'All'
? undefined
: currentStatus.value === 'ACTIVE'
? 'ACTIVE'
: 'INACTIVE',
});
if (result) {
totalBranch.value = result.total;
maxPageBranch.value = Math.ceil(result.total / pageSizeBranch.value);
branch.value = result.result;
}
}
watch([inputSearch, currentStatus], async () => {
await fetchList();
});
</script>
<template>
<div
class="row justify-between bordered-b surface-3 full-width"
style="z-index: 1"
>
<div class="row items-center col-12 col-md">
<q-btn
round
icon="mdi-arrow-left"
flat
dense
@click="$emit('back')"
class="q-mr-md"
/>
<q-card-section
class="q-pa-sm q-pt-md q-mr-md q-mb-sm"
:class="{
color__purple: customerType === 'CORP',
color__green: customerType === 'PERS',
}"
style="border-radius: 0 0 40px 40px; position: relative"
>
<q-avatar no-padding size="50px">
<img :src="currentCustomerUrlImage ?? '/no-profile.png'" />
</q-avatar>
</q-card-section>
<div>
<div>{{ currentCustomerName }}</div>
<div class="row items-center">
<i
class="isax isax-frame5"
style="font-size: 1rem; color: var(--stone-6)"
/>
<div class="q-px-sm">
{{ '10' }}
</div>
<q-icon name="mdi-home" size="16px" style="color: var(--stone-6)" />
<div class="q-px-sm">
{{ '2' }}
</div>
</div>
</div>
</div>
<div
class="row items-center justify-end q-px-md col-12 col-sm q-py-sm no-wrap"
>
<q-input
lazy-rules="ondemand"
outlined
dense
class="col-6"
:label="$t('search')"
:bg-color="$q.dark.isActive ? 'dark' : 'white'"
v-model="inputSearch"
debounce="500"
>
<template v-slot:prepend>
<q-icon name="mdi-magnify" />
</template>
</q-input>
<q-select
lazy-rules="ondemand"
id="select-status"
for="select-status"
v-model="currentStatus"
outlined
dense
option-value="value"
option-label="label"
class="col q-pl-sm"
map-options
emit-value
:hide-dropdown-icon="$q.screen.lt.sm"
:options="[
{ label: $t('all'), value: 'All' },
{ label: $t('statusACTIVE'), value: 'ACTIVE' },
{ label: $t('statusINACTIVE'), value: 'INACTIVE' },
]"
></q-select>
<q-btn-toggle
id="btn-mode"
v-model="modeView"
dense
class="no-shadow bordered rounded surface-1 q-ml-sm"
:toggle-color="$q.dark.isActive ? 'grey-9' : 'grey-2'"
size="xs"
:options="[
{ value: true, slot: 'folder' },
{ value: false, slot: 'list' },
]"
>
<template v-slot:folder>
<q-icon
id="icon-mode-grid"
name="mdi-view-grid-outline"
size="16px"
class="q-px-sm q-py-sm rounded"
:style="{
color: $q.dark.isActive
? modeView
? '#C9D3DB'
: '#787B7C'
: modeView
? '#787B7C'
: '#C9D3DB',
}"
/>
</template>
<template v-slot:list>
<q-icon
id="icon-mode-list"
name="mdi-format-list-bulleted"
class="q-px-sm q-py-xs rounded"
size="16px"
:style="{
color: $q.dark.isActive
? modeView === true
? '#C9D3DB'
: '#787B7C'
: modeView === false
? '#787B7C'
: '#C9D3DB',
}"
/>
</template>
</q-btn-toggle>
</div>
</div>
<div
class="row q-pa-md col scroll full-width surface-2"
:class="{
'justify-center': totalBranch === 0,
'items-center': totalBranch === 0,
}"
>
<NoData v-if="totalBranch === 0" :not-found="!!inputSearch" />
<div style="width: 100%" v-else>
<q-table
v-if="branch"
flat
class="full-width"
bordered
:rows-per-page-options="[0]"
:rows="branch"
:columns="columns"
:grid="modeView"
card-container-class="row q-col-gutter-md"
row-key="name"
hide-pagination
:visible-columns="branchFieldSelected"
>
<template #header>
<q-tr style="background-color: hsla(var(--info-bg) / 0.07)">
<q-th
v-for="(v, i) in fieldDisplay"
:key="v"
:class="{ 'text-left': i === 0 }"
>
{{ $t(v) }}
</q-th>
<q-th auto-width />
</q-tr>
</template>
<template #body="props">
<q-tr
:class="{
'app-text-muted': props.row.status === 'INACTIVE',
'cursor-pointer': props.row._count?.branch !== 0,
}"
:props="props"
@click="$emit('viewDetail', props.row, props.rowIndex)"
>
<q-td v-if="branchFieldSelected.includes('branchName')">
<div class="row items-center no-wrap">
<div
:class="{
'status-active': props.row.status !== 'INACTIVE',
'status-inactive': props.row.status === 'INACTIVE',
}"
class="q-mr-md"
style="display: flex; margin-bottom: var(--size-2)"
>
<div
class="branch-card__icon"
:class="{ 'branch-card__dark': $q.dark.isActive }"
>
<q-icon
size="md"
style="scale: 0.8"
name="mdi-office-building-outline"
/>
</div>
</div>
<div class="col" style="min-width: fit-content">
<div class="col">
{{
$i18n.locale === 'en-US'
? props.row.nameEN
: props.row.name
}}
</div>
<div class="col app-text-muted">
{{ props.row.code }}
</div>
</div>
</div>
</q-td>
<q-td
v-if="branchFieldSelected.includes('customerBranchFormTab')"
class="text-center"
>
{{ props.row.branchNo || '-' }}
</q-td>
<q-td
v-if="branchFieldSelected.includes('address')"
class="text-center"
>
{{
$i18n.locale === 'en-US'
? `${props.row.addressEN || ''} ${props.row.subDistrict?.nameEN || ''} ${props.row.district?.nameEN || ''} ${props.row.province?.nameEN || ''}`
: `${props.row.address || ''} ${props.row.subDistrict?.name || ''} ${props.row.district?.name || ''} ${props.row.province?.name || ''}`
}}
</q-td>
<q-td
v-if="branchFieldSelected.includes('telephone')"
class="text-center"
>
{{ props.row.telephoneNo || '-' }}
</q-td>
<q-td
v-if="branchFieldSelected.includes('businessTypePure')"
class="text-center"
>
{{ useOptionStore().mapOption(props.row.bussinessType) || '-' }}
</q-td>
<q-td
v-if="branchFieldSelected.includes('totalEmployee')"
class="text-center"
>
{{ props.row._count?.employee }}
</q-td>
<q-td>
<q-btn
icon="mdi-eye-outline"
:id="`btn-eye-${props.row.customerName}`"
size="sm"
dense
round
flat
@click="$emit('viewDetail', props.row, props.rowIndex)"
/>
</q-td>
</q-tr>
</template>
<template #item="props">
<div class="col-12 col-md-6">
<BranchCardCustomer
class="surface-1"
:inactive="props.row.status === 'INACTIVE'"
:color="customerType === 'CORP' ? 'corp' : 'pers'"
:badgeField="['status']"
:data="{
customerBranchFormTab: props.row.branchNo,
branchName: props.row.name,
address:
$i18n.locale === 'en-US'
? `${props.row.addressEN || ''} ${props.row.subDistrict?.nameEN || ''} ${props.row.district?.nameEN || ''} ${props.row.province?.nameEN || ''}`
: `${props.row.address || ''} ${props.row.subDistrict?.name || ''} ${props.row.district?.name || ''} ${props.row.province?.name || ''}`,
telephone: props.row.telephoneNo,
businessTypePure: useOptionStore().mapOption(
props.row.bussinessType,
),
totalEmployee: props.row._count?.employee,
}"
:visible-columns="branchFieldSelected"
@view-detail="$emit('viewDetail', props.row, props.rowIndex)"
/>
</div>
</template>
</q-table>
</div>
</div>
<div class="row justify-between items-center q-px-md q-py-sm surface-2">
<div class="col"></div>
<div class="app-text-muted col text-center">
{{
$t('recordsPage', {
resultcurrentPage: branch?.length,
total: totalBranch,
})
}}
</div>
<div class="col-4 flex justify-end">
<PaginationComponent
v-model:current-page="currentPageBranch"
v-model:max-page="maxPageBranch"
:fetch-data="
async () => {
await fetchList();
flowStore.rotate();
}
"
/>
</div>
</div>
</template>
<style scoped>
.branch-card__icon {
--_branch-card-bg: var(--pink-6-hsl);
background-color: hsla(var(--_branch-card-bg) / 0.15);
border-radius: 50%;
padding: var(--size-1);
position: relative;
transform: rotate(45deg);
&.branch-card__dark {
--_branch-card-bg: var(--pink-5-hsl);
}
&::after {
content: ' ';
display: block;
block-size: 0.5rem;
aspect-ratio: 1;
position: absolute;
border-radius: 50%;
right: -0.25rem;
top: calc(50% - 0.25rem);
bottom: calc(50% - 0.25rem);
background-color: hsla(var(--_branch-status-color) / 1);
}
& :deep(.q-icon) {
transform: rotate(-45deg);
color: hsla(var(--_branch-card-bg) / 1);
}
}
</style>

View file

@ -0,0 +1,200 @@
<script lang="ts" setup>
import { ref, watch } from 'vue';
import { QSelect } from 'quasar';
import { selectFilterOptionRefMod } from 'stores/utils';
import { getRole } from 'src/services/keycloak';
import { onMounted } from 'vue';
import {
SaveButton,
EditButton,
CancelButton,
DeleteButton,
} from 'src/components/button';
defineProps<{
prefixId?: string;
outlined?: boolean;
readonly?: boolean;
create?: boolean;
actionDisabled?: boolean;
customerType?: 'CORP' | 'PERS';
}>();
defineEmits<{
(e: 'save'): void;
(e: 'edit'): void;
(e: 'delete'): void;
(e: 'cancel'): void;
}>();
const personName = defineModel<string>('personName', { required: true });
const customerName = defineModel<string>('customerName', { required: true });
const customerNameEN = defineModel<string>('customerNameEn', {
required: true,
});
const taxNo = defineModel<string | null>('taxNo');
const registeredBranchId = defineModel<string>('registeredBranchId', {
required: true,
});
const branchOptions = defineModel<{ id: string; name: string }[]>(
'branchOptions',
{ default: [] },
);
const filteredBranchOptions = ref<Record<string, unknown>[]>([]);
let branchFilter: (
value: string,
update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;
onMounted(() => {
branchFilter = selectFilterOptionRefMod(
branchOptions,
filteredBranchOptions,
'name',
);
});
watch(
() => branchOptions.value,
() => {
branchFilter = selectFilterOptionRefMod(
branchOptions,
filteredBranchOptions,
'name',
);
},
);
</script>
<template>
<div class="row q-col-gutter-sm">
<div class="col-12 text-weight-bold text-body1 row items-center">
<q-icon
flat
size="xs"
class="q-pa-sm rounded q-mr-xs"
color="info"
name="mdi-office-building-outline"
style="background-color: var(--surface-3)"
/>
<span>{{ $t('customer.form.group.basicInfo') }}</span>
<EditButton
v-if="readonly && !create"
type="button"
@click="$emit('edit')"
class="q-ml-auto"
:disabled="actionDisabled"
/>
<DeleteButton
v-if="readonly && !create"
@click="$emit('delete')"
type="button"
class="q-ml-sm"
:disabled="actionDisabled"
/>
<SaveButton
v-if="!readonly"
@click="$emit('save')"
class="q-ml-auto"
:disabled="actionDisabled"
/>
<CancelButton
v-if="!readonly && !create"
type="button"
class="q-ml-sm"
:disabled="actionDisabled"
@click="$emit('cancel')"
/>
</div>
<q-select
outlined
clearable
use-input
fill-input
emit-value
map-options
hide-selected
hide-bottom-space
dense
class="col-12 col-md-4"
option-value="id"
input-debounce="0"
option-label="name"
lazy-rules="ondemand"
v-model="registeredBranchId"
:readonly="readonly"
:options="filteredBranchOptions"
:hide-dropdown-icon="readonly"
:label="$t('registeredBranch')"
:for="`${prefixId}-input-source-nationality`"
:rules="[
(val) => {
const roles = getRole() || [];
return (
['admin', 'system', 'head_of_admin'].some((v) =>
roles.includes(v),
) ||
!!val ||
$t('form.error.required')
);
},
]"
@filter="branchFilter"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
{{ $t('noResults') }}
</q-item-section>
</q-item>
</template>
</q-select>
<q-input
lazy-rules="ondemand"
dense
outlined
hide-bottom-space
:label="$t('customer.form.customerName')"
v-model="customerName"
class="col-12 col-md-4"
:readonly="readonly"
:for="`${prefixId}-input-company-name`"
/>
<q-input
lazy-rules="ondemand"
dense
outlined
:readonly="readonly"
hide-bottom-space
:label="$t('customer.form.customerNameEN')"
v-model="customerNameEN"
:for="`${prefixId}-input-company-name-en`"
class="col-12 col-md-4"
/>
<q-input
lazy-rules="ondemand"
dense
outlined
:readonly="readonly"
hide-bottom-space
v-model="personName"
:label="$t('customer.form.personName')"
:for="`${prefixId}-input-person-name`"
:rules="[(v: string) => !!v || $t('form.error.required')]"
class="col-12 col-md-4"
/>
<q-input
lazy-rules="ondemand"
dense
outlined
v-if="customerType === 'PERS'"
:readonly="readonly"
hide-bottom-space
:label="$t('customer.form.taxIdentificationNumber')"
v-model="taxNo"
:for="`${prefixId}-input-tax-no`"
class="col-12 col-md-4"
/>
</div>
</template>

View file

@ -0,0 +1,291 @@
<script setup lang="ts">
import { ref } from 'vue';
import FormAddress from 'src/components/02_personnel-management/FormAddress.vue';
import FormBusiness from './EmployerFormBusiness.vue';
import FormContact from './EmployerFormContact.vue';
import { CustomerCreate } from 'src/stores/customer/types';
import { dateFormat, parseAndFormatDate } from 'src/utils/datetime';
import { EditButton } from 'src/components/button';
import DeleteButton from 'src/components/button/DeleteButton.vue';
import SaveButton from 'src/components/button/SaveButton.vue';
import CancelButton from 'src/components/button/CancelButton.vue';
const item = defineModel<NonNullable<CustomerCreate['customerBranch']>[number]>(
'customerBranch',
{
required: true,
default: [],
},
);
const tab = ref('main');
defineEmits<{
(e: 'edit'): void;
(e: 'save'): void;
(e: 'cancel'): void;
(e: 'delete'): void;
}>();
defineProps<{
readonly?: boolean;
prefixId?: string;
actionDisabled?: boolean;
customerType?: 'CORP' | 'PERS';
}>();
</script>
<template>
<span
class="col-12 text-weight-bold row items-center q-mb-sm"
:style="{ opacity: actionDisabled ? '.5' : undefined }"
:id="`form-branch-customer-no-${item.branchNo}`"
>
{{ $t('customer.form.branch.title', { name: item.branchNo || 0 }) }}
<EditButton
v-if="readonly"
@click="$emit('edit')"
class="q-ml-auto"
type="button"
:disabled="actionDisabled"
/>
<DeleteButton
v-if="readonly"
@click="$emit('delete')"
class="q-ml-sm"
type="button"
:disabled="actionDisabled"
/>
<SaveButton
v-if="!readonly"
@click="$emit('save')"
class="q-ml-auto"
type="submit"
:disabled="actionDisabled"
/>
<CancelButton
v-if="!readonly"
@click="$emit('cancel')"
class="q-ml-sm"
type="button"
:disabled="actionDisabled"
/>
</span>
<div class="col-12" :style="{ opacity: actionDisabled ? '.5' : undefined }">
<div class="rounded bordered">
<q-tabs
v-model="tab"
dense
align="left"
class="bordered-b"
active-color="primary"
no-caps
>
<q-tab name="main" label="Main"></q-tab>
<q-tab name="address" label="Address"></q-tab>
<q-tab name="business" label="Business"></q-tab>
<q-tab name="contact" label="Contact"></q-tab>
</q-tabs>
<q-tab-panels v-model="tab">
<q-tab-panel name="main">
<div class="row q-col-gutter-md">
<q-input
lazy-rules="ondemand"
dense
outlined
:readonly="readonly"
hide-bottom-space
:label="$t('customerBranch.form.no')"
v-model="item.branchNo"
:for="`${prefixId}-input-branch-branch-no`"
type="number"
class="col-12 col-md-2"
/>
<q-input
lazy-rules="ondemand"
dense
outlined
readonly
hide-bottom-space
:label="$t('customerBranch.form.code')"
:model-value="item.code || '-'"
:for="`${prefixId}-input-branch-branch-code`"
class="col-12 col-md-4"
/>
<q-input
lazy-rules="ondemand"
dense
outlined
:readonly="readonly"
hide-bottom-space
:label="$t('customerBranch.form.taxNo')"
v-model="item.taxNo"
:for="`${prefixId}-input-branch-tax-no`"
type="number"
class="col-12 col-md-4"
/>
<q-input
lazy-rules="ondemand"
dense
outlined
:readonly="readonly"
hide-bottom-space
:label="$t('customerBranch.form.name')"
v-model="item.name"
:for="`${prefixId}-input-branch-tax-no`"
class="col-12 col-md-6"
/>
<q-input
lazy-rules="ondemand"
dense
outlined
:readonly="readonly"
hide-bottom-space
:label="$t('customerBranch.form.nameEN')"
v-model="item.nameEN"
:for="`${prefixId}-input-branch-tax-no`"
class="col-12 col-md-6"
/>
<q-input
lazy-rules="ondemand"
dense
outlined
v-if="customerType === 'CORP'"
:readonly="readonly"
hide-bottom-space
:label="$t('customerBranch.form.registerName')"
v-model="item.registerName"
:for="`${prefixId}-input-branch-register-name`"
class="col-12 col-md-4"
/>
<q-input
lazy-rules="ondemand"
dense
outlined
:readonly="readonly"
hide-bottom-space
v-if="customerType === 'CORP'"
:label="$t('customerBranch.form.authorizedCapital')"
v-model="item.authorizedCapital"
:for="`${prefixId}-input-branch-authorized-capital`"
class="col-12 col-md-4"
/>
<VueDatePicker
:id="`${prefixId}-picker-date-register-date`"
:teleport="true"
utc
v-if="customerType === 'CORP'"
auto-apply
v-model="item.registerDate"
:dark="$q.dark.isActive"
:locale="$i18n.locale === 'th-th' ? 'th' : 'en'"
:enableTimePicker="false"
:disabled="readonly"
class="col-md-4 col-12"
>
<template #year="{ value }">
{{ $i18n.locale === 'th-th' ? value + 543 : value }}
</template>
<template #year-overlay-value="{ value }">
{{ $i18n.locale === 'th-th' ? value + 543 : value }}
</template>
<template #trigger>
<q-input
lazy-rules="ondemand"
:for="`${prefixId}-input-start-date`"
:id="`${prefixId}-input-start-date`"
:label="$t('customerBranch.form.registerDate')"
dense
outlined
:readonly="readonly"
placeholder="DD/MM/YYYY"
:mask="readonly ? '' : '##/##/####'"
:model-value="
item.registerDate
? readonly
? dateFormat(item.registerDate)
: dateFormat(item.registerDate, false, false, true)
: undefined
"
@update:model-value="
(v) => {
if (readonly && v && v.toString().length === 10) {
const _date = parseAndFormatDate(v, $i18n.locale);
if (_date) {
item.registerDate?.setDate(_date.getDate());
item.registerDate?.setMonth(_date.getMonth());
item.registerDate?.setFullYear(_date.getFullYear());
} else {
item.registerDate = null;
}
}
}
"
>
<template v-slot:prepend>
<q-icon
size="xs"
name="mdi-calendar-blank-outline"
class="cursor-pointer"
color="primary"
/>
</template>
<template v-slot:append>
<q-icon
v-if="!item.registerDate && readonly"
name="mdi-close-circle"
class="cursor-pointer app-text-muted"
size="sm"
@click="item.registerDate = null"
/>
</template>
</q-input>
</template>
</VueDatePicker>
</div>
</q-tab-panel>
<q-tab-panel name="address">
<FormAddress
:prefix-id="prefixId || 'employer'"
hide-title
dense
:readonly="readonly"
outlined
:title="$t('form.address')"
v-model:address="item.address"
v-model:addressEN="item.addressEN"
v-model:province-id="item.provinceId"
v-model:district-id="item.districtId"
v-model:sub-district-id="item.subDistrictId"
:addressTitle="$t('form.address')"
:addressTitleEN="$t('form.address', { suffix: '(EN)' })"
/>
</q-tab-panel>
<q-tab-panel name="business">
<FormBusiness
dense
outlined
:prefix-id="prefixId || 'employer'"
:readonly="readonly"
v-model:employment-office="item.employmentOffice"
v-model:bussiness-type="item.bussinessType"
v-model:bussiness-type-en="item.bussinessTypeEN"
v-model:job-position="item.jobPosition"
v-model:job-position-en="item.jobPositionEN"
v-model:job-description="item.jobDescription"
v-model:sale-employee="item.saleEmployee"
v-model:pay-date="item.payDate"
v-model:wage-rate="item.wageRate"
/>
</q-tab-panel>
<q-tab-panel name="contact">
<FormContact
:readonly="readonly"
v-model:email="item.email"
v-model:telephone="item.telephoneNo"
/>
</q-tab-panel>
</q-tab-panels>
</div>
</div>
</template>

View file

@ -0,0 +1,286 @@
<script setup lang="ts">
import { selectFilterOptionRefMod } from 'src/stores/utils';
import { dateFormat, parseAndFormatDate } from 'src/utils/datetime';
import { onMounted, watch } from 'vue';
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
const { locale } = useI18n({ useScope: 'global' });
const employmentOffice = defineModel<string>('employmentOffice');
const bussinessType = defineModel<string>('bussinessType');
const jobPosition = defineModel<string>('jobPosition');
const bussinessTypeEN = defineModel<string>('bussinessTypeEn');
const jobPositionEN = defineModel<string>('jobPositionEn');
const jobDescription = defineModel<string>('jobDescription');
const payDate = defineModel<Date | null | string>('payDate');
const wageRate = defineModel<number>('wageRate');
const saleEmployee = defineModel<string>('saleEmployee');
const rawOption = ref();
const typeBusinessOption = ref([]);
const jobPositionOption = ref([]);
defineProps<{
title?: string;
dense?: boolean;
outlined?: boolean;
readonly?: boolean;
prefixId: string;
}>();
onMounted(async () => {
const resultOption = await fetch('/option/option.json');
rawOption.value = await resultOption.json();
if (locale.value === 'en-US') {
typeBusinessOption.value = rawOption.value.eng.businessType;
jobPositionOption.value = rawOption.value.eng.position;
}
if (locale.value === 'th-th') {
typeBusinessOption.value = rawOption.value.tha.businessType;
jobPositionOption.value = rawOption.value.tha.position;
}
});
watch(typeBusinessOption, () => {
typeBusinessFilter = selectFilterOptionRefMod(
typeBusinessOption,
typeBusinessOptions,
'label',
);
});
watch(jobPositionOption, () => {
jobPositionFilter = selectFilterOptionRefMod(
jobPositionOption,
jobPositionOptions,
'label',
);
});
const typeBusinessOptions = ref<Record<string, unknown>[]>([]);
let typeBusinessFilter = selectFilterOptionRefMod(
typeBusinessOption,
typeBusinessOptions,
'label',
);
const jobPositionOptions = ref<Record<string, unknown>[]>([]);
let jobPositionFilter = selectFilterOptionRefMod(
jobPositionOption,
jobPositionOptions,
'label',
);
</script>
<template>
<div class="col-12 row q-col-gutter-sm">
<q-input
lazy-rules="ondemand"
:for="`${prefixId}-input-employment-office`"
:id="`${prefixId}-input-employment-office`"
:dense="dense"
outlined
:readonly="readonly"
hide-bottom-space
class="col-12"
:label="$t('inputCustomerAddress')"
v-model="employmentOffice"
/>
<q-select
outlined
clearable
use-input
fill-input
emit-value
map-options
hide-selected
hide-bottom-space
input-debounce="0"
option-value="value"
option-label="label"
lazy-rules="ondemand"
v-model="bussinessType"
class="col-md-6 col-12"
:dense="dense"
:readonly="readonly"
:label="$t('businessType')"
:options="typeBusinessOptions"
:for="`${prefixId}-select-business-type`"
@filter="typeBusinessFilter"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
{{ $t('noResults') }}
</q-item-section>
</q-item>
</template>
</q-select>
<q-input
lazy-rules="ondemand"
:for="`${prefixId}-input-bussiness-type-en`"
:id="`${prefixId}-input-bussiness-type-en`"
:dense="dense"
outlined
:readonly="readonly"
hide-bottom-space
class="col-md-6 col-12"
:label="$t('businessTypeEN')"
v-model="bussinessTypeEN"
/>
<q-select
outlined
clearable
use-input
fill-input
emit-value
map-options
hide-selected
hide-bottom-space
input-debounce="0"
option-value="value"
option-label="label"
lazy-rules="ondemand"
v-model="jobPosition"
class="col-md-6 col-12"
:dense="dense"
:readonly="readonly"
:label="$t('jobPosition')"
:options="jobPositionOptions"
:for="`${prefixId}-select-job-position`"
@filter="jobPositionFilter"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
{{ $t('noResults') }}
</q-item-section>
</q-item>
</template>
</q-select>
<q-input
lazy-rules="ondemand"
:for="`${prefixId}-input-job-position-en`"
:id="`${prefixId}-input-job-position-en`"
:dense="dense"
outlined
:readonly="readonly"
hide-bottom-space
class="col-md-6 col-12"
:label="$t('jobPositionEN')"
v-model="jobPositionEN"
/>
<q-input
lazy-rules="ondemand"
:for="`${prefixId}-input-job-description`"
:id="`${prefixId}-input-job-description`"
:dense="dense"
outlined
:readonly="readonly"
hide-bottom-space
class="col-md-6 col-12"
:label="$t('jobDescription')"
v-model="jobDescription"
/>
<VueDatePicker
:id="`${prefixId}-date-picker-start-date`"
:teleport="true"
utc
autoApply
v-model="payDate"
:dark="$q.dark.isActive"
:locale="$i18n.locale === 'th-th' ? 'th' : 'en'"
:enableTimePicker="false"
:disabled="readonly"
class="col-md-3 col-12"
>
<template #year="{ value }">
{{ $i18n.locale === 'th-th' ? value + 543 : value }}
</template>
<template #year-overlay-value="{ value }">
{{ $i18n.locale === 'th-th' ? value + 543 : value }}
</template>
<template #trigger>
<q-input
lazy-rules="ondemand"
:for="`${prefixId}-input-start-date`"
:id="`${prefixId}-input-start-date`"
:label="$t('payDay')"
:dense="dense"
outlined
:readonly="readonly"
placeholder="DD/MM/YYYY"
:mask="readonly ? '' : '##/##/####'"
:model-value="
payDate
? readonly
? dateFormat(payDate)
: dateFormat(payDate, false, false, true)
: undefined
"
@update:model-value="
(v) => {
if (v && v.toString().length === 10) {
payDate = parseAndFormatDate(v, locale);
}
}
"
>
<template v-slot:prepend>
<q-icon
size="xs"
name="mdi-calendar-blank-outline"
class="cursor-pointer"
color="primary"
/>
</template>
<template v-slot:append>
<q-icon
v-if="payDate && !readonly"
name="mdi-close-circle"
class="cursor-pointer app-text-muted"
size="sm"
@click="payDate = undefined"
/>
</template>
</q-input>
</template>
</VueDatePicker>
<q-input
lazy-rules="ondemand"
:for="`${prefixId}-input-pay-rate`"
:id="`${prefixId}-input-pay-rate`"
:dense="dense"
outlined
:readonly="readonly"
hide-bottom-space
class="col-md-3 col-6"
:label="$t('payRate')"
v-model="wageRate"
/>
<q-input
lazy-rules="ondemand"
:for="`${prefixId}-input-sales-person`"
:id="`${prefixId}-input-sales-person`"
:dense="dense"
outlined
:readonly="readonly"
hide-bottom-space
class="col-6"
:label="$t('salesPerson')"
v-model="saleEmployee"
/>
</div>
</template>

View file

@ -0,0 +1,37 @@
<script lang="ts" setup>
defineProps<{
readonly?: boolean;
prefixId?: string;
}>();
const mail = defineModel<string>('mail');
const telephone = defineModel<string>('telephone');
</script>
<template>
<div class="col-md-9 col-12 row q-col-gutter-md">
<q-input
lazy-rules="ondemand"
:for="`${prefixId}-input-mail`"
:id="`${prefixId}-input-mail`"
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-md-6 col-12"
:label="$t('formDialogInputEmail')"
v-model="mail"
/>
<q-input
lazy-rules="ondemand"
:for="`${prefixId}-input-telephone`"
:id="`${prefixId}-input-telephone`"
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-md-6 col-12"
:label="$t('formDialogInputTelephone')"
v-model="telephone"
/>
</div>
</template>