Compare commits
228 commits
version-0.
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65dcd138db | ||
| e6d06b39da | |||
| 3cab6cc0e5 | |||
|
|
9994366c74 | ||
|
|
f4db5ad855 | ||
|
|
15a812b50e | ||
|
|
f7a8416e7a | ||
|
|
79d6482caa | ||
|
|
75d5c7dfe8 | ||
|
|
637eeab3c2 | ||
| 2b1e3b12a4 | |||
|
|
a1ed625d32 | ||
|
|
59a3f964c4 | ||
|
|
2afb5ea7e9 | ||
| aaf776639d | |||
| 04c463a717 | |||
| 8e65a1c5a2 | |||
| 21fc2d5d96 | |||
| 73f43c2a29 | |||
| 16ea66484d | |||
| 90f31a0c87 | |||
| d1785faed2 | |||
| f68e8cf675 | |||
| cd4b087fec | |||
|
|
8a0340f588 | ||
| 2b9c8aa613 | |||
|
|
eebd585554 | ||
|
|
db5262da42 | ||
|
|
72b0e89642 | ||
|
|
2320883cb6 | ||
|
|
0e6bee7b62 | ||
| 5c867a496d | |||
|
|
d06c26c3c8 | ||
|
|
c4f088c5cb | ||
| 6cf8cf28aa | |||
|
|
1249f67a0f | ||
|
|
05d38b1ab3 | ||
|
|
d09484a52a | ||
|
|
d8d02a679d | ||
|
|
11047e569d | ||
|
|
f3b5b25bf3 | ||
|
|
e817e8fd05 | ||
|
|
18e5517325 | ||
|
|
5e13864d4a | ||
| 61dca12e5a | |||
| aa908f0c3d | |||
| 80056f8e0b | |||
|
|
02bb682150 | ||
| d2acd6ba4c | |||
| d53eb15a88 | |||
|
|
35e23aa291 | ||
|
|
00f9b5f4c4 | ||
|
|
7846950802 | ||
|
|
ef8e294ae4 | ||
| 016a54e45e | |||
|
|
4e887fdff8 | ||
| ded56d103b | |||
|
|
0d708405f6 | ||
| 2099031fa8 | |||
|
|
fd12f32ab0 | ||
| f10103b5d0 | |||
|
|
d6e366f788 | ||
| 52c384f0fb | |||
|
|
fcafaeebc0 | ||
|
|
0e57a3daf6 | ||
|
|
0ad017309f | ||
| b9cfb6274b | |||
|
|
5becbae369 | ||
| 7c3a9818c2 | |||
| 56f0a86845 | |||
| 492f341e68 | |||
|
|
49897ff007 | ||
| c430b6082e | |||
|
|
e6f8870cdf | ||
|
|
67cde37e34 | ||
|
|
763ac07be7 | ||
|
|
c07efa7318 | ||
|
|
507141dca5 | ||
| 73b2d52fb0 | |||
|
|
e6ecd39d24 | ||
|
|
c0a2d3769d | ||
|
|
05f7c886d6 | ||
|
|
93c54c0dd1 | ||
|
|
ef4c84341c | ||
| 09b51d601e | |||
| c29e1d4ec5 | |||
|
|
d89925dee9 | ||
|
|
3e24a46f66 | ||
|
|
764d9bab3f | ||
|
|
e5b2114984 | ||
|
|
37c9f5fcd5 | ||
|
|
67a69b85e0 | ||
|
|
eb88cc4269 | ||
|
|
ec780f2018 | ||
|
|
31b4daf42b | ||
|
|
5fad663a6e | ||
|
|
d4a9be9236 | ||
|
|
e33191dcd4 | ||
|
|
fd28f36876 | ||
|
|
a05c1e7004 | ||
|
|
db2a094471 | ||
|
|
9aba48401a | ||
|
|
a3c51f5f52 | ||
|
|
d44850a9ae | ||
|
|
b86891c8c2 | ||
|
|
473e272328 | ||
|
|
02d02cf3a1 | ||
|
|
044a530b8d | ||
|
|
b21949712b | ||
|
|
42e545dd66 | ||
|
|
263c703e69 | ||
|
|
968aa04aa9 | ||
|
|
8ca3f784f1 | ||
|
|
d60f858582 | ||
|
|
4ec3506e62 | ||
|
|
f3342dfbda | ||
|
|
9b56896695 | ||
|
|
7d4b38369c | ||
|
|
b977f86de9 | ||
|
|
da52bfbcbd | ||
|
|
cdb38e301e | ||
|
|
7f56a6219a | ||
|
|
642dec8de9 | ||
|
|
1360aca7e9 | ||
|
|
dbca22f639 | ||
|
|
b5abf693c2 | ||
|
|
8ef2ca2e96 | ||
|
|
ad715b20a2 | ||
|
|
915ce6f70b | ||
|
|
12b49a2a07 | ||
|
|
40e6d1ba1c | ||
|
|
22e11cf699 | ||
|
|
af1f74bdda | ||
|
|
ed55d07e38 | ||
|
|
ac50ef1c7c | ||
|
|
d4f021d0e6 | ||
|
|
3ddea74b73 | ||
|
|
2ac31c2e4c | ||
|
|
e3f86136e7 | ||
|
|
577da39cf0 | ||
|
|
30d2126161 | ||
|
|
b86c0a1e7a | ||
|
|
d59642bcb3 | ||
|
|
0e5378455b | ||
|
|
0c59ef89ca | ||
|
|
052722eb14 | ||
|
|
db7f96fc02 | ||
|
|
04765a656a | ||
|
|
c3989768ed | ||
|
|
e19d3f05f1 | ||
|
|
fe2860d818 | ||
|
|
25216de820 | ||
|
|
76cfb5fcec | ||
|
|
7d1a32efb4 | ||
|
|
9999a49fa0 | ||
|
|
6b55701afb | ||
|
|
fc7a94d7a2 | ||
|
|
2ba4758e50 | ||
|
|
5bed71053e | ||
|
|
bc53399153 | ||
|
|
059c6d3afc | ||
|
|
6117867aba | ||
|
|
7d425332c3 | ||
|
|
9539adee36 | ||
|
|
14487ed849 | ||
|
|
4a195494d6 | ||
|
|
5e155cfb0c | ||
|
|
78a59e277f | ||
|
|
844cf176df | ||
|
|
a89de83fe9 | ||
|
|
2b310c667d | ||
|
|
7679c076a7 | ||
|
|
088f829146 | ||
|
|
b9f1d04105 | ||
|
|
34f5b6474b | ||
|
|
84591ae719 | ||
|
|
8b2e3f76c4 | ||
|
|
1e34f18366 | ||
|
|
f08c83c98b | ||
|
|
c481266654 | ||
|
|
a59e0c5157 | ||
|
|
a5791a1b54 | ||
|
|
f646b3c9ba | ||
|
|
9dcec6b4c6 | ||
|
|
03adabeabd | ||
|
|
942449e373 | ||
|
|
dd09a8cb23 | ||
|
|
33e040c21a | ||
|
|
ca57f4790c | ||
|
|
e957672c91 | ||
|
|
436bfa41bb | ||
|
|
d4cab27aaf | ||
|
|
f286f6a16e | ||
|
|
f516212b6c | ||
|
|
011c65dcf8 | ||
|
|
3c4573192f | ||
|
|
48a1800b54 | ||
|
|
963ed11073 | ||
|
|
8b933455d1 | ||
|
|
e9d995fa3e | ||
|
|
2269038e11 | ||
|
|
d880e1a1c5 | ||
|
|
5e76c4d50d | ||
|
|
2d7b0189ee | ||
|
|
c991e9e03f | ||
|
|
aaa448fa0c | ||
|
|
58231aa936 | ||
|
|
701b90d89a | ||
|
|
8799799214 | ||
|
|
57660d7991 | ||
|
|
9ab61d8ded | ||
|
|
09f368f516 | ||
|
|
d831cd0799 | ||
|
|
860b0b8f47 | ||
|
|
41d02273ee | ||
|
|
19ee1040d4 | ||
|
|
5c01882a34 | ||
|
|
5edff6a5a8 | ||
|
|
1b475933da | ||
|
|
40942fc420 | ||
|
|
df9430af24 | ||
|
|
a74c4648c6 | ||
|
|
3f15ce3ca6 | ||
|
|
105e91a655 | ||
|
|
0f252b3080 | ||
|
|
80c8a0d8b4 | ||
|
|
543c28e162 | ||
|
|
8354b6b40a |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 7.4 KiB |
|
|
@ -183,15 +183,15 @@
|
||||||
|
|
||||||
"prefix": [
|
"prefix": [
|
||||||
{
|
{
|
||||||
"label": "Mr",
|
"label": "MR",
|
||||||
"value": "mr"
|
"value": "mr"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Mrs",
|
"label": "MRS",
|
||||||
"value": "mrs"
|
"value": "mrs"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Miss",
|
"label": "MISS",
|
||||||
"value": "miss"
|
"value": "miss"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -89,15 +89,7 @@ defineProps<{
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<q-separator />
|
||||||
style="
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: 1px;
|
|
||||||
background: hsla(0 0% 0% / 0.1);
|
|
||||||
margin-bottom: var(--size-2);
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<slot name="data"></slot>
|
<slot name="data"></slot>
|
||||||
<template v-if="!$slots.data">
|
<template v-if="!$slots.data">
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -159,42 +159,6 @@ function formatCode(input: string | undefined, type: 'code' | 'number') {
|
||||||
]"
|
]"
|
||||||
for="input-name-en"
|
for="input-name-en"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-select
|
|
||||||
v-if="
|
|
||||||
typeBranch !== 'headOffice' &&
|
|
||||||
isRoleInclude(['head_of_admin', 'head_of_account'])
|
|
||||||
"
|
|
||||||
outlined
|
|
||||||
use-input
|
|
||||||
fill-input
|
|
||||||
emit-value
|
|
||||||
map-options
|
|
||||||
hide-selected
|
|
||||||
hide-bottom-space
|
|
||||||
input-debounce="0"
|
|
||||||
option-label="label"
|
|
||||||
option-value="value"
|
|
||||||
class="col-2"
|
|
||||||
dense
|
|
||||||
for="input-branch-status"
|
|
||||||
:readonly="readonly || isRoleInclude(['head_of_account'])"
|
|
||||||
:options="['Virtual', 'Branch']"
|
|
||||||
:hide-dropdown-icon="readonly"
|
|
||||||
:label="$t('general.branchStatus')"
|
|
||||||
:model-value="virtual ? 'Virtual' : 'Branch'"
|
|
||||||
@update:model-value="(v) => (virtual = v === 'Virtual')"
|
|
||||||
:rules="[(val) => val && val.length > 0]"
|
|
||||||
:error-message="$t('form.error.required')"
|
|
||||||
>
|
|
||||||
<template v-slot:no-option>
|
|
||||||
<q-item>
|
|
||||||
<q-item-section class="text-grey">
|
|
||||||
{{ $t('general.noData') }}
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</template>
|
|
||||||
</q-select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12 row q-col-gutter-sm">
|
<div class="col-12 row q-col-gutter-sm">
|
||||||
|
|
|
||||||
|
|
@ -262,7 +262,7 @@ function deleteFile(name: string) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-file
|
<q-file
|
||||||
v-if="userType"
|
v-if="userType && !readonly"
|
||||||
ref="attachmentRef"
|
ref="attachmentRef"
|
||||||
for="input-attachment"
|
for="input-attachment"
|
||||||
:dense="dense"
|
:dense="dense"
|
||||||
|
|
|
||||||
|
|
@ -253,16 +253,13 @@ watch(
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
:readonly="readonly"
|
:readonly="readonly"
|
||||||
:label="$t('form.email')"
|
:label="$t('form.email')"
|
||||||
:rules="
|
:rules="[
|
||||||
readonly
|
(val) => (val && val.length > 0) || $t('form.error.required'),
|
||||||
? undefined
|
(v: string) =>
|
||||||
: [
|
!v ||
|
||||||
(v: string) =>
|
/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/g.test(v) ||
|
||||||
!v ||
|
$t('form.error.invalid'),
|
||||||
/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/g.test(v) ||
|
]"
|
||||||
$t('form.error.invalid'),
|
|
||||||
]
|
|
||||||
"
|
|
||||||
class="col-md-3 col-6"
|
class="col-md-3 col-6"
|
||||||
:model-value="readonly ? email || '-' : email"
|
:model-value="readonly ? email || '-' : email"
|
||||||
@update:model-value="(v) => (typeof v === 'string' ? (email = v) : '')"
|
@update:model-value="(v) => (typeof v === 'string' ? (email = v) : '')"
|
||||||
|
|
@ -296,15 +293,11 @@ watch(
|
||||||
:readonly="readonly"
|
:readonly="readonly"
|
||||||
:label="$t('form.birthDate')"
|
:label="$t('form.birthDate')"
|
||||||
:disabled-dates="disabledAfterToday"
|
:disabled-dates="disabledAfterToday"
|
||||||
:rules="
|
:rules="[
|
||||||
employee
|
(val: string) =>
|
||||||
? []
|
!!val ||
|
||||||
: [
|
$t('form.error.selectField', { field: $t('form.birthDate') }),
|
||||||
(val: string) =>
|
]"
|
||||||
!!val ||
|
|
||||||
$t('form.error.selectField', { field: $t('form.birthDate') }),
|
|
||||||
]
|
|
||||||
"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-input
|
<q-input
|
||||||
|
|
|
||||||
1656
src/components/03_customer-management/DialogEmployee.vue
Normal file
1772
src/components/03_customer-management/DrawerEmployee.vue
Normal file
|
|
@ -268,6 +268,7 @@ const insuranceCompanyFilter = selectFilterOptionRefMod(
|
||||||
|
|
||||||
<div class="col-md col-6">
|
<div class="col-md col-6">
|
||||||
<DatePicker
|
<DatePicker
|
||||||
|
:label="$t('customerEmployee.formHealthCheck.coverageStartDate')"
|
||||||
v-model="checkup.coverageStartDate"
|
v-model="checkup.coverageStartDate"
|
||||||
:id="`${prefixId}-input-coverage-start-date`"
|
:id="`${prefixId}-input-coverage-start-date`"
|
||||||
:readonly="readonly || checkup.statusSave"
|
:readonly="readonly || checkup.statusSave"
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import useOptionStore from 'stores/options';
|
||||||
|
|
||||||
import DatePicker from '../shared/DatePicker.vue';
|
import DatePicker from '../shared/DatePicker.vue';
|
||||||
|
|
||||||
|
import { dateFormat } from 'src/utils/datetime';
|
||||||
|
|
||||||
const optionStore = useOptionStore();
|
const optionStore = useOptionStore();
|
||||||
const { locale } = useI18n();
|
const { locale } = useI18n();
|
||||||
|
|
||||||
|
|
@ -18,8 +20,8 @@ const issuePlace = defineModel<string>('issuePlace');
|
||||||
const issueCountry = defineModel<string>('issueCountry');
|
const issueCountry = defineModel<string>('issueCountry');
|
||||||
const issueDate = defineModel<Date | null | string>('issueDate');
|
const issueDate = defineModel<Date | null | string>('issueDate');
|
||||||
const type = defineModel<string>('type');
|
const type = defineModel<string>('type');
|
||||||
const expireDate = defineModel<Date>('expireDate');
|
const expireDate = defineModel<Date | string>('expireDate');
|
||||||
const birthDate = defineModel<Date>('birthDate');
|
const birthDate = defineModel<Date | string>('birthDate');
|
||||||
const workerStatus = defineModel<string>('workerStatus');
|
const workerStatus = defineModel<string>('workerStatus');
|
||||||
const nationality = defineModel<string>('nationality');
|
const nationality = defineModel<string>('nationality');
|
||||||
const gender = defineModel<string>('gender');
|
const gender = defineModel<string>('gender');
|
||||||
|
|
@ -32,6 +34,8 @@ const firstName = defineModel<string>('firstName');
|
||||||
const namePrefix = defineModel<string>('namePrefix');
|
const namePrefix = defineModel<string>('namePrefix');
|
||||||
const passportNumber = defineModel<string>('passportNumber');
|
const passportNumber = defineModel<string>('passportNumber');
|
||||||
|
|
||||||
|
const file = defineModel<File>('file');
|
||||||
|
|
||||||
const passportValidator = /[a-zA-Z]{1}[a-zA-Z0-9]{1}[0-9]{5,7}$/;
|
const passportValidator = /[a-zA-Z]{1}[a-zA-Z0-9]{1}[0-9]{5,7}$/;
|
||||||
|
|
||||||
const genderOptions = ref<Record<string, unknown>[]>([]);
|
const genderOptions = ref<Record<string, unknown>[]>([]);
|
||||||
|
|
@ -177,6 +181,30 @@ watch(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function browse() {
|
||||||
|
inputFile?.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputFile = (() => {
|
||||||
|
const _element = document.createElement('input');
|
||||||
|
_element.type = 'file';
|
||||||
|
_element.accept = 'image/jpeg,image/png';
|
||||||
|
_element.addEventListener('change', change);
|
||||||
|
return _element;
|
||||||
|
})();
|
||||||
|
|
||||||
|
async function change(e: Event) {
|
||||||
|
const _element = e.target as HTMLInputElement | null;
|
||||||
|
const _file = _element?.files?.[0];
|
||||||
|
|
||||||
|
if (_file) {
|
||||||
|
const newFileName = `passport-${dateFormat(new Date().toISOString())}-${_file.name}`;
|
||||||
|
const renamedFile = new File([_file], newFileName, { type: _file.type });
|
||||||
|
|
||||||
|
file.value = renamedFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => namePrefix.value,
|
() => namePrefix.value,
|
||||||
(v) => {
|
(v) => {
|
||||||
|
|
@ -221,20 +249,14 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="q-col-gutter-sm" :class="{ row: $q.screen.gt.sm }">
|
<div class="q-col-gutter-sm" :class="{ row: $q.screen.gt.sm }">
|
||||||
<div
|
<div v-if="!ocr">
|
||||||
class="col row justify-center q-col-gutter-sml"
|
<q-btn
|
||||||
style="max-height: 50%"
|
flat
|
||||||
v-if="!ocr"
|
color="primary"
|
||||||
>
|
icon="mdi-upload-box-outline"
|
||||||
<q-avatar
|
@click="() => browse()"
|
||||||
style="border: 1px dashed; border-color: black"
|
:disable="readonly"
|
||||||
square
|
></q-btn>
|
||||||
size="100px"
|
|
||||||
font-size="50px"
|
|
||||||
color="grey-4"
|
|
||||||
text-color="grey"
|
|
||||||
icon="mdi-image-outline"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="row q-col-gutter-sm"
|
class="row q-col-gutter-sm"
|
||||||
|
|
|
||||||
|
|
@ -28,20 +28,22 @@ const arrivalAt = defineModel<string>('arrivalAt');
|
||||||
const arrivalTMNo = defineModel<string>('arrivalTmNo');
|
const arrivalTMNo = defineModel<string>('arrivalTmNo');
|
||||||
const arrivalTM = defineModel<string>('arrivalTm');
|
const arrivalTM = defineModel<string>('arrivalTm');
|
||||||
const mrz = defineModel<string>('mrz');
|
const mrz = defineModel<string>('mrz');
|
||||||
const entryCount = defineModel<number>('entryCount');
|
const entryCount = defineModel<number | string>('entryCount');
|
||||||
const issuePlace = defineModel<string>('issuePlace');
|
const issuePlace = defineModel<string>('issuePlace');
|
||||||
const issueCountry = defineModel<string>('issueCountry');
|
const issueCountry = defineModel<string>('issueCountry');
|
||||||
const issueDate = defineModel<Date | null | string>('visaIssueDate');
|
const issueDate = defineModel<Date | null | string>('visaIssueDate');
|
||||||
const type = defineModel<string>('type');
|
const type = defineModel<string>('type');
|
||||||
const expireDate = defineModel<Date>('expireDate');
|
const expireDate = defineModel<Date | string>('expireDate');
|
||||||
const remark = defineModel<string>('remark');
|
const remark = defineModel<string>('remark');
|
||||||
const workerType = defineModel<string>('workerType');
|
const workerType = defineModel<string>('workerType');
|
||||||
const number = defineModel<string>('number');
|
const number = defineModel<string>('number');
|
||||||
|
const reportDate = defineModel<Date | null | string>('reportDate');
|
||||||
|
|
||||||
const calculatedVisaDate = computed(() => {
|
//
|
||||||
if (!issueDate.value) return undefined;
|
// const calculatedVisaDate = computed(() => {
|
||||||
return calculate90DayNext(issueDate.value);
|
// if (!issueDate.value) return undefined;
|
||||||
});
|
// return calculate90DayNext(issueDate.value);
|
||||||
|
// });
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
title?: string;
|
title?: string;
|
||||||
|
|
@ -138,6 +140,10 @@ watch(
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
//
|
||||||
|
// watch([() => issueDate.value], () => {
|
||||||
|
// reportDate.value = calculate90DayNext(issueDate.value);
|
||||||
|
// });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -151,7 +157,7 @@ watch(
|
||||||
name="mdi-passport"
|
name="mdi-passport"
|
||||||
style="background-color: var(--surface-3)"
|
style="background-color: var(--surface-3)"
|
||||||
/>
|
/>
|
||||||
{{ title }}
|
{{ $t(title) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
@ -371,10 +377,12 @@ watch(
|
||||||
<DatePicker
|
<DatePicker
|
||||||
:id="`${prefixId}-date-picker-visa-issuance`"
|
:id="`${prefixId}-date-picker-visa-issuance`"
|
||||||
:readonly
|
:readonly
|
||||||
:disabled="!readonly"
|
|
||||||
:label="$t('customerEmployee.form.visa90Day')"
|
:label="$t('customerEmployee.form.visa90Day')"
|
||||||
:model-value="calculatedVisaDate"
|
v-model="reportDate"
|
||||||
clearable
|
clearable
|
||||||
|
:rules="[
|
||||||
|
(val) => (val && val.length > 0) || $t('form.error.required'),
|
||||||
|
]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ const prop = withDefaults(
|
||||||
inTable?: boolean;
|
inTable?: boolean;
|
||||||
addButton?: boolean;
|
addButton?: boolean;
|
||||||
prefixId?: string;
|
prefixId?: string;
|
||||||
|
hideAction?: boolean;
|
||||||
|
hideDelete?: boolean;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
gridView: false,
|
gridView: false,
|
||||||
|
|
@ -139,8 +141,9 @@ defineEmits<{
|
||||||
<q-avatar size="md">
|
<q-avatar size="md">
|
||||||
<q-img
|
<q-img
|
||||||
:src="
|
:src="
|
||||||
`${baseUrl}/employee/${props.row.id}/image/${props.row.selectedImage}` ||
|
props.row.selectedImage
|
||||||
`/images/employee-avatar-${props.row.gender}.png`
|
? `${baseUrl}/employee/${props.row.id}/image/${props.row.selectedImage}`
|
||||||
|
: `/images/employee-avatar-${props.row.gender}.png`
|
||||||
"
|
"
|
||||||
class="text-center"
|
class="text-center"
|
||||||
:ratio="1"
|
:ratio="1"
|
||||||
|
|
@ -265,9 +268,10 @@ defineEmits<{
|
||||||
@click.stop="$emit('view', props.row)"
|
@click.stop="$emit('view', props.row)"
|
||||||
/>
|
/>
|
||||||
<KebabAction
|
<KebabAction
|
||||||
v-if="!inTable"
|
v-if="!inTable && !hideAction"
|
||||||
:id-name="props.row.firstName"
|
:id-name="props.row.firstName"
|
||||||
:status="props.row.status"
|
:status="props.row.status"
|
||||||
|
:hide-delete="hideDelete"
|
||||||
@view="$emit('view', props.row)"
|
@view="$emit('view', props.row)"
|
||||||
@edit="$emit('edit', props.row)"
|
@edit="$emit('edit', props.row)"
|
||||||
@delete="$emit('delete', props.row)"
|
@delete="$emit('delete', props.row)"
|
||||||
|
|
@ -280,9 +284,11 @@ defineEmits<{
|
||||||
<template v-slot:item="props">
|
<template v-slot:item="props">
|
||||||
<div class="col-12 col-md-3 col-sm-6">
|
<div class="col-12 col-md-3 col-sm-6">
|
||||||
<PersonCard
|
<PersonCard
|
||||||
|
history
|
||||||
|
:hide-delete="hideDelete"
|
||||||
|
:hide-action="hideAction"
|
||||||
:id="`card-${props.row.firstNameEN}`"
|
:id="`card-${props.row.firstNameEN}`"
|
||||||
:field-selected="fieldSelected"
|
:field-selected="fieldSelected"
|
||||||
history
|
|
||||||
:prefix-id="props.row.firstNameEN ?? props.rowIndex"
|
:prefix-id="props.row.firstNameEN ?? props.rowIndex"
|
||||||
:data="{
|
:data="{
|
||||||
code: props.row.code,
|
code: props.row.code,
|
||||||
|
|
@ -290,9 +296,9 @@ defineEmits<{
|
||||||
$i18n.locale === 'eng'
|
$i18n.locale === 'eng'
|
||||||
? `${props.row.firstNameEN} ${props.row.lastNameEN} `.trim()
|
? `${props.row.firstNameEN} ${props.row.lastNameEN} `.trim()
|
||||||
: `${props.row.firstName} ${props.row.lastName} `.trim(),
|
: `${props.row.firstName} ${props.row.lastName} `.trim(),
|
||||||
img:
|
img: props.row.selectedImage
|
||||||
`${baseUrl}/employee/${props.row.id}/image/${props.row.selectedImage}` ||
|
? `${baseUrl}/employee/${props.row.id}/image/${props.row.selectedImage}`
|
||||||
`/images/employee-avatar-${props.row.gender}.png`,
|
: `/images/employee-avatar-${props.row.gender}.png`,
|
||||||
fallbackImg: `/images/employee-avatar-${props.row.gender}.png`,
|
fallbackImg: `/images/employee-avatar-${props.row.gender}.png`,
|
||||||
male: props.row.gender === 'male',
|
male: props.row.gender === 'male',
|
||||||
female: props.row.gender === 'female',
|
female: props.row.gender === 'female',
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ defineProps<{
|
||||||
employeeOwnerOption?: CustomerBranch[];
|
employeeOwnerOption?: CustomerBranch[];
|
||||||
prefixId: string;
|
prefixId: string;
|
||||||
showBtnSave?: boolean;
|
showBtnSave?: boolean;
|
||||||
|
disableCustomerSelect?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
|
|
@ -117,12 +118,16 @@ defineEmits<{
|
||||||
|
|
||||||
<div class="col-12 row" style="gap: var(--size-2)">
|
<div class="col-12 row" style="gap: var(--size-2)">
|
||||||
<SelectCustomer
|
<SelectCustomer
|
||||||
|
id="form-select-customer-branch-id"
|
||||||
|
for="form-select-customer-branch-id"
|
||||||
v-model:value="customerBranchId"
|
v-model:value="customerBranchId"
|
||||||
v-model:value-option="currentCustomerBranch"
|
v-model:value-option="currentCustomerBranch"
|
||||||
:label="$t('customer.form.branchCode')"
|
:label="$t('customer.form.branchCode')"
|
||||||
class="col-12 field-two"
|
class="col-12 field-two"
|
||||||
|
simple
|
||||||
required
|
required
|
||||||
:readonly
|
:readonly
|
||||||
|
:disabled="disableCustomerSelect && !readonly"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-input
|
<q-input
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import { QField } from 'quasar';
|
||||||
defineProps<{
|
defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
onDrawer?: boolean;
|
onDrawer?: boolean;
|
||||||
|
hideAction?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
@ -201,6 +202,7 @@ onMounted(async () => {
|
||||||
:class="{ 'q-ml-lg': $q.screen.gt.xs, 'q-mt-sm': $q.screen.lt.sm }"
|
:class="{ 'q-ml-lg': $q.screen.gt.xs, 'q-mt-sm': $q.screen.lt.sm }"
|
||||||
>
|
>
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
|
:disable="hideAction"
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
two-way
|
two-way
|
||||||
:model-value="flowData.status !== 'INACTIVE'"
|
:model-value="flowData.status !== 'INACTIVE'"
|
||||||
|
|
@ -609,7 +611,7 @@ onMounted(async () => {
|
||||||
</span>
|
</span>
|
||||||
</q-item>
|
</q-item>
|
||||||
</template>
|
</template>
|
||||||
<template #append>
|
<template v-if="!readonly" #append>
|
||||||
<q-icon
|
<q-icon
|
||||||
name="mdi-menu-down"
|
name="mdi-menu-down"
|
||||||
:class="{ rotated: responsibleMenu }"
|
:class="{ rotated: responsibleMenu }"
|
||||||
|
|
|
||||||
|
|
@ -167,26 +167,28 @@ withDefaults(
|
||||||
<div class="col-12 full-width">
|
<div class="col-12 full-width">
|
||||||
<q-table
|
<q-table
|
||||||
:rows-per-page-options="[0]"
|
:rows-per-page-options="[0]"
|
||||||
:rows="[
|
:rows="
|
||||||
{
|
[
|
||||||
label: $t('productService.product.salePrice'),
|
priceDisplay.price && {
|
||||||
pricePerUnit: price,
|
label: $t('productService.product.salePrice'),
|
||||||
calcVat,
|
pricePerUnit: price,
|
||||||
vatIncluded,
|
calcVat,
|
||||||
},
|
vatIncluded,
|
||||||
{
|
},
|
||||||
label: $t('productService.product.agentPrice'),
|
priceDisplay.agentPrice && {
|
||||||
calcVat: agentPriceCalcVat,
|
label: $t('productService.product.agentPrice'),
|
||||||
vatIncluded: agentPriceVatIncluded,
|
calcVat: agentPriceCalcVat,
|
||||||
pricePerUnit: agentPrice,
|
vatIncluded: agentPriceVatIncluded,
|
||||||
},
|
pricePerUnit: agentPrice,
|
||||||
{
|
},
|
||||||
label: $t('productService.product.processingPrice'),
|
priceDisplay.serviceCharge && {
|
||||||
calcVat: serviceChargeCalcVat,
|
label: $t('productService.product.processingPrice'),
|
||||||
vatIncluded: serviceChargeVatIncluded,
|
calcVat: serviceChargeCalcVat,
|
||||||
pricePerUnit: serviceCharge,
|
vatIncluded: serviceChargeVatIncluded,
|
||||||
},
|
pricePerUnit: serviceCharge,
|
||||||
]"
|
},
|
||||||
|
].filter(Boolean)
|
||||||
|
"
|
||||||
:columns
|
:columns
|
||||||
hide-bottom
|
hide-bottom
|
||||||
bordered
|
bordered
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
onDrawer?: boolean;
|
onDrawer?: boolean;
|
||||||
inputOnly?: boolean;
|
inputOnly?: boolean;
|
||||||
|
disableToggle?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
|
|
@ -76,6 +77,7 @@ defineEmits<{
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
two-way
|
two-way
|
||||||
|
:disable="disableToggle"
|
||||||
:model-value="status !== 'INACTIVE'"
|
:model-value="status !== 'INACTIVE'"
|
||||||
@click="
|
@click="
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -195,8 +197,8 @@ defineEmits<{
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(
|
:deep(
|
||||||
.q-item__section.column.q-item__section--side.justify-center.q-item__section--avatar.q-focusable.relative-position.cursor-pointer
|
.q-item__section.column.q-item__section--side.justify-center.q-item__section--avatar.q-focusable.relative-position.cursor-pointer
|
||||||
) {
|
) {
|
||||||
justify-content: start !important;
|
justify-content: start !important;
|
||||||
padding-right: 8px !important;
|
padding-right: 8px !important;
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
|
|
@ -208,15 +210,15 @@ defineEmits<{
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(
|
:deep(
|
||||||
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
|
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
|
||||||
) {
|
) {
|
||||||
color: var(--brand-1);
|
color: var(--brand-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(
|
:deep(
|
||||||
.q-item.q-item-type.row.no-wrap.q-item--dense.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable.expansion-rounded.surface-2
|
.q-item.q-item-type.row.no-wrap.q-item--dense.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable.expansion-rounded.surface-2
|
||||||
.q-focus-helper
|
.q-focus-helper
|
||||||
) {
|
) {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,18 @@
|
||||||
import SelectCustomer from '../shared/select/SelectCustomer.vue';
|
import SelectCustomer from '../shared/select/SelectCustomer.vue';
|
||||||
import SelectBranch from '../shared/select/SelectBranch.vue';
|
import SelectBranch from '../shared/select/SelectBranch.vue';
|
||||||
|
|
||||||
|
import { CustomerBranch } from 'src/stores/customer';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
const branchId = defineModel<string>('branchId');
|
const branchId = defineModel<string>('branchId');
|
||||||
const customerBranchId = defineModel<string>('customerBranchId');
|
const customerBranchId = defineModel<string>('customerBranchId');
|
||||||
const agentPrice = defineModel<boolean>('agentPrice');
|
const agentPrice = defineModel<boolean>('agentPrice');
|
||||||
const special = defineModel<boolean>('special');
|
const special = defineModel<boolean>('special');
|
||||||
|
|
||||||
|
const customerBranchOption = defineModel<CustomerBranch>(
|
||||||
|
'customerBranchOption',
|
||||||
|
);
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
outlined?: boolean;
|
outlined?: boolean;
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
|
|
@ -67,8 +74,12 @@ defineEmits<{
|
||||||
required
|
required
|
||||||
:readonly
|
:readonly
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SelectCustomer
|
<SelectCustomer
|
||||||
|
id="about-select-customer-branch-id"
|
||||||
|
for="about-select-customer-branch-id"
|
||||||
v-model:value="customerBranchId"
|
v-model:value="customerBranchId"
|
||||||
|
v-model:value-option="customerBranchOption"
|
||||||
:label="$t('quotation.customer')"
|
:label="$t('quotation.customer')"
|
||||||
:creatable-disabled-text="`(${$t('form.error.selectField', {
|
:creatable-disabled-text="`(${$t('form.error.selectField', {
|
||||||
field: $t('quotation.branchVirtual'),
|
field: $t('quotation.branchVirtual'),
|
||||||
|
|
@ -88,14 +99,14 @@ defineEmits<{
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
:deep(
|
:deep(
|
||||||
label.q-field.row.no-wrap.items-start.q-field--outlined.q-select.field-one
|
label.q-field.row.no-wrap.items-start.q-field--outlined.q-select.field-one
|
||||||
) {
|
) {
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(
|
:deep(
|
||||||
label.q-field.row.no-wrap.items-start.q-field--outlined.q-select.field-two
|
label.q-field.row.no-wrap.items-start.q-field--outlined.q-select.field-two
|
||||||
) {
|
) {
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -58,16 +58,15 @@ const currentBtnOpen = ref<{ title: string; opened: boolean[] }[]>([
|
||||||
|
|
||||||
function calcPrice(c: (typeof rows.value)[number]) {
|
function calcPrice(c: (typeof rows.value)[number]) {
|
||||||
const originalPrice = c.pricePerUnit;
|
const originalPrice = c.pricePerUnit;
|
||||||
const finalPriceWithVat = precisionRound(
|
const finalPricePerUnit = precisionRound(
|
||||||
originalPrice + originalPrice * (config.value?.vat || 0.07),
|
originalPrice +
|
||||||
|
(c.product[props.agentPrice ? 'agentPriceCalcVat' : 'calcVat']
|
||||||
|
? originalPrice * (config.value?.vat || 0.07)
|
||||||
|
: 0),
|
||||||
);
|
);
|
||||||
const finalPriceNoVat = finalPriceWithVat / (1 + (config.value?.vat || 0.07));
|
const price = finalPricePerUnit * c.amount - c.discount;
|
||||||
|
|
||||||
const price = finalPriceNoVat * c.amount - c.discount;
|
return precisionRound(price);
|
||||||
const vat = c.product[props.agentPrice ? 'agentPriceCalcVat' : 'calcVat']
|
|
||||||
? (finalPriceNoVat * c.amount - c.discount) * (config.value?.vat || 0.07)
|
|
||||||
: 0;
|
|
||||||
return precisionRound(price + vat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const discount4Show = ref<string[]>([]);
|
const discount4Show = ref<string[]>([]);
|
||||||
|
|
@ -435,8 +434,20 @@ watch(
|
||||||
<q-td align="right">
|
<q-td align="right">
|
||||||
{{
|
{{
|
||||||
formatNumberDecimal(
|
formatNumberDecimal(
|
||||||
props.row.pricePerUnit * props.row.amount -
|
props.row.product[
|
||||||
props.row.discount,
|
agentPrice ? 'agentPriceCalcVat' : 'calcVat'
|
||||||
|
]
|
||||||
|
? precisionRound(
|
||||||
|
(props.row.pricePerUnit *
|
||||||
|
(1 + (config?.vat || 0.07)) *
|
||||||
|
props.row.amount -
|
||||||
|
props.row.discount) /
|
||||||
|
(1 + (config?.vat || 0.07)),
|
||||||
|
)
|
||||||
|
: precisionRound(
|
||||||
|
props.row.pricePerUnit * props.row.amount -
|
||||||
|
props.row.discount,
|
||||||
|
),
|
||||||
2,
|
2,
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
@ -448,9 +459,12 @@ watch(
|
||||||
agentPrice ? 'agentPriceCalcVat' : 'calcVat'
|
agentPrice ? 'agentPriceCalcVat' : 'calcVat'
|
||||||
]
|
]
|
||||||
? precisionRound(
|
? precisionRound(
|
||||||
(props.row.pricePerUnit * props.row.amount -
|
((props.row.pricePerUnit *
|
||||||
props.row.discount) *
|
(1 + (config?.vat || 0.07)) *
|
||||||
(config?.vat || 0.07),
|
props.row.amount -
|
||||||
|
props.row.discount) /
|
||||||
|
(1 + (config?.vat || 0.07))) *
|
||||||
|
0.07,
|
||||||
)
|
)
|
||||||
: 0,
|
: 0,
|
||||||
2,
|
2,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { QTableProps } from 'quasar';
|
import { QTableProps } from 'quasar';
|
||||||
import { dateFormat } from 'src/utils/datetime';
|
import { dateFormat, dateFormatJS } from 'src/utils/datetime';
|
||||||
|
|
||||||
import { formatNumberDecimal } from 'stores/utils';
|
import { formatNumberDecimal } from 'stores/utils';
|
||||||
|
|
||||||
|
|
@ -19,6 +19,8 @@ const props = withDefaults(
|
||||||
page?: number;
|
page?: number;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
hideBtnPreview?: boolean;
|
hideBtnPreview?: boolean;
|
||||||
|
hideAction?: boolean;
|
||||||
|
hideDelete?: boolean;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
row: () => [],
|
row: () => [],
|
||||||
|
|
@ -84,11 +86,11 @@ defineEmits<{
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
||||||
<q-td v-if="visibleColumns.includes('createdAt')">
|
<q-td v-if="visibleColumns.includes('createdAt')">
|
||||||
{{ dateFormat(props.row.createdAt) }}
|
{{ dateFormatJS({ date: props.row.createdAt }) }}
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
||||||
<q-td v-if="visibleColumns.includes('dueDate')">
|
<q-td v-if="visibleColumns.includes('dueDate')">
|
||||||
{{ dateFormat(props.row.dueDate) }}
|
{{ dateFormatJS({ date: props.row.dueDate }) }}
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
||||||
<q-td v-if="visibleColumns.includes('contactName')">
|
<q-td v-if="visibleColumns.includes('contactName')">
|
||||||
|
|
@ -147,12 +149,12 @@ defineEmits<{
|
||||||
flat
|
flat
|
||||||
@click.stop="$emit('view', props.row)"
|
@click.stop="$emit('view', props.row)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<KebabAction
|
<KebabAction
|
||||||
|
v-if="!hideAction"
|
||||||
:idName="`btn-kebab-${props.row.workName}`"
|
:idName="`btn-kebab-${props.row.workName}`"
|
||||||
status="'ACTIVE'"
|
status="'ACTIVE'"
|
||||||
hide-toggle
|
hide-toggle
|
||||||
hide-delete
|
:hide-delete
|
||||||
:hide-edit="hideEdit"
|
:hide-edit="hideEdit"
|
||||||
@view="$emit('view', props.row)"
|
@view="$emit('view', props.row)"
|
||||||
@edit="$emit('edit', props.row)"
|
@edit="$emit('edit', props.row)"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
import SelectInput from '../shared/SelectInput.vue';
|
import SelectInput from '../shared/SelectInput.vue';
|
||||||
import useOptionStore from 'src/stores/options';
|
import useOptionStore from 'src/stores/options';
|
||||||
|
import { Icon } from '@iconify/vue/dist/iconify.js';
|
||||||
|
import { useInstitution } from 'src/stores/institution';
|
||||||
|
|
||||||
const optionStore = useOptionStore();
|
const optionStore = useOptionStore();
|
||||||
|
|
||||||
|
|
@ -10,6 +14,11 @@ defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
onDrawer?: boolean;
|
onDrawer?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'deleteAttachment', name: string): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const attachmentRef = ref();
|
||||||
|
|
||||||
const group = defineModel('group', { default: '' });
|
const group = defineModel('group', { default: '' });
|
||||||
const name = defineModel('name', { default: '' });
|
const name = defineModel('name', { default: '' });
|
||||||
|
|
@ -17,8 +26,19 @@ const nameEn = defineModel('nameEn', { default: '' });
|
||||||
const contactName = defineModel('contactName', { default: '' });
|
const contactName = defineModel('contactName', { default: '' });
|
||||||
const email = defineModel('email', { default: '' });
|
const email = defineModel('email', { default: '' });
|
||||||
const contactTel = defineModel('contactTel', { default: '' });
|
const contactTel = defineModel('contactTel', { default: '' });
|
||||||
|
const attachment = defineModel<File[]>('attachment');
|
||||||
|
const attachmentList =
|
||||||
|
defineModel<{ name: string; url: string }[]>('attachmentList');
|
||||||
|
|
||||||
type Options = { label: string; value: string };
|
type Options = { label: string; value: string };
|
||||||
|
|
||||||
|
function openNewTab(url: string) {
|
||||||
|
window.open(url, '_blank');
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteAttachment(name: string) {
|
||||||
|
emit('deleteAttachment', name);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="row col-12">
|
<div class="row col-12">
|
||||||
|
|
@ -162,6 +182,78 @@ type Options = { label: string; value: string };
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
||||||
|
<q-file
|
||||||
|
v-if="!readonly"
|
||||||
|
ref="attachmentRef"
|
||||||
|
for="input-attachment"
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
multiple
|
||||||
|
append
|
||||||
|
:readonly
|
||||||
|
:label="$t('personnel.form.attachment')"
|
||||||
|
class="col"
|
||||||
|
v-model="attachment"
|
||||||
|
>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<Icon
|
||||||
|
icon="material-symbols:attach-file"
|
||||||
|
width="20px"
|
||||||
|
style="color: var(--brand-1)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-slot:file="file">
|
||||||
|
<div class="row full-width items-center">
|
||||||
|
<span class="col ellipsis">
|
||||||
|
{{ file.file.name }}
|
||||||
|
</span>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
flat
|
||||||
|
padding="2 2"
|
||||||
|
class="app-text-muted"
|
||||||
|
icon="mdi-close-circle"
|
||||||
|
@click.stop="attachmentRef.removeAtIndex(file.index)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-file>
|
||||||
|
|
||||||
|
<div v-if="attachmentList && attachmentList?.length > 0" class="col-12">
|
||||||
|
<q-list bordered separator class="rounded" style="padding: 0">
|
||||||
|
<q-item
|
||||||
|
id="attachment-file"
|
||||||
|
for="attachment-file"
|
||||||
|
v-for="item in attachmentList"
|
||||||
|
clickable
|
||||||
|
:key="item.url"
|
||||||
|
class="items-center row"
|
||||||
|
@click="() => openNewTab(item.url)"
|
||||||
|
>
|
||||||
|
<q-item-section>
|
||||||
|
<div class="row items-center justify-between">
|
||||||
|
<div class="col">
|
||||||
|
{{ item.name }}
|
||||||
|
</div>
|
||||||
|
<q-btn
|
||||||
|
v-if="!readonly"
|
||||||
|
id="delete-file"
|
||||||
|
rounded
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
unelevated
|
||||||
|
size="md"
|
||||||
|
icon="mdi-trash-can-outline"
|
||||||
|
class="app-text-negative"
|
||||||
|
@click.stop="deleteAttachment(item.name)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -27,26 +27,38 @@ withDefaults(
|
||||||
class="app-text-muted q-pr-sm"
|
class="app-text-muted q-pr-sm"
|
||||||
:width="iconSize || '2rem'"
|
:width="iconSize || '2rem'"
|
||||||
/>
|
/>
|
||||||
<span class="row col">
|
<span :id="`dd-wrapper-${label}`" class="row col">
|
||||||
<span class="col-12 app-text-muted-2" style="font-size: 10px">
|
<span
|
||||||
|
:id="`dd-label-${label}`"
|
||||||
|
class="col-12 app-text-muted-2"
|
||||||
|
style="font-size: 10px"
|
||||||
|
>
|
||||||
{{ label }}
|
{{ label }}
|
||||||
</span>
|
</span>
|
||||||
<span class="col-12 ellipsis">
|
<span :id="`dd-value-wrapper-${label}`" class="col-12 ellipsis">
|
||||||
<slot name="value">
|
<slot name="value">
|
||||||
<span
|
<span
|
||||||
:class="{ 'link cursor-pointer': clickable }"
|
:class="{ 'link cursor-pointer': clickable }"
|
||||||
v-if="typeof value === 'string'"
|
v-if="typeof value === 'string'"
|
||||||
@click="$emit('labelClick', value, null)"
|
@click="clickable ? $emit('labelClick', value, null) : undefined"
|
||||||
|
:id="`link-${value}`"
|
||||||
|
:for="`link-${value}`"
|
||||||
>
|
>
|
||||||
{{ value }}
|
{{ value }}
|
||||||
<q-tooltip v-if="tooltip" :delay="500">{{ value }}</q-tooltip>
|
<q-tooltip v-if="tooltip" :delay="500">{{ value }}</q-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<span v-else :class="{ 'link cursor-pointer': clickable }">
|
<span
|
||||||
|
:id="`dd-value-${label}`"
|
||||||
|
v-else
|
||||||
|
:class="{ 'link cursor-pointer': clickable }"
|
||||||
|
>
|
||||||
<span
|
<span
|
||||||
v-for="(item, index) in value"
|
v-for="(item, index) in value"
|
||||||
:key="index"
|
:key="index"
|
||||||
@click="$emit('labelClick', item, index)"
|
@click="$emit('labelClick', item, index)"
|
||||||
class="link cursor-pointer"
|
class="link cursor-pointer"
|
||||||
|
:id="`link-${item}`"
|
||||||
|
:for="`link-${item}`"
|
||||||
>
|
>
|
||||||
{{ item }}
|
{{ item }}
|
||||||
<span v-if="index < value.length - 1">, </span>
|
<span v-if="index < value.length - 1">, </span>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,10 @@ defineProps<{
|
||||||
const quotationId = defineModel<string>('quotationId', {
|
const quotationId = defineModel<string>('quotationId', {
|
||||||
required: true,
|
required: true,
|
||||||
});
|
});
|
||||||
|
const isDebitNote = defineModel<boolean>('isDebitNote', {
|
||||||
|
required: false,
|
||||||
|
default: false,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="row col-12">
|
<div class="row col-12">
|
||||||
|
|
@ -37,6 +41,7 @@ const quotationId = defineModel<string>('quotationId', {
|
||||||
cancelIncludeDebitNote: true,
|
cancelIncludeDebitNote: true,
|
||||||
hasCancel: true,
|
hasCancel: true,
|
||||||
}"
|
}"
|
||||||
|
@selected="(v) => (isDebitNote = v.isDebitNote)"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import {
|
||||||
UndoButton,
|
UndoButton,
|
||||||
} from 'components/button';
|
} from 'components/button';
|
||||||
|
|
||||||
withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
title: string;
|
title: string;
|
||||||
category?: string;
|
category?: string;
|
||||||
|
|
@ -42,6 +42,11 @@ const drawerOpen = defineModel<boolean>('drawerOpen', {
|
||||||
const myForm = ref();
|
const myForm = ref();
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
|
if (props.beforeClose) {
|
||||||
|
drawerOpen.value = props.beforeClose
|
||||||
|
? props.beforeClose()
|
||||||
|
: !drawerOpen.value;
|
||||||
|
}
|
||||||
if (myForm.value) {
|
if (myForm.value) {
|
||||||
myForm.value.resetValidation();
|
myForm.value.resetValidation();
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +67,6 @@ async function onValidationError(ref: any) {
|
||||||
@show="show"
|
@show="show"
|
||||||
@before-hide="reset"
|
@before-hide="reset"
|
||||||
@hide="close"
|
@hide="close"
|
||||||
@update:model-value="(v) => (drawerOpen = beforeClose ? beforeClose() : v)"
|
|
||||||
:width="$q.screen.gt.xs ? windowSize * 0.85 : windowSize"
|
:width="$q.screen.gt.xs ? windowSize * 0.85 : windowSize"
|
||||||
v-model="drawerOpen"
|
v-model="drawerOpen"
|
||||||
behavior="mobile"
|
behavior="mobile"
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ defineProps<{
|
||||||
color="grey"
|
color="grey"
|
||||||
icon="mdi-close"
|
icon="mdi-close"
|
||||||
v-close-popup
|
v-close-popup
|
||||||
|
@click="cancel"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const pageSize = defineModel<number>({ required: true });
|
const pageSize = defineModel<number>({ required: true });
|
||||||
|
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
fetchData?: (...args: unknown[]) => void;
|
||||||
|
}>(),
|
||||||
|
{},
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -10,7 +17,12 @@ const pageSize = defineModel<number>({ required: true });
|
||||||
:key="v"
|
:key="v"
|
||||||
clickable
|
clickable
|
||||||
v-close-popup
|
v-close-popup
|
||||||
@click="pageSize = v"
|
@click="
|
||||||
|
() => {
|
||||||
|
pageSize = v;
|
||||||
|
fetchData();
|
||||||
|
}
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label>{{ v }}</q-item-label>
|
<q-item-label>{{ v }}</q-item-label>
|
||||||
|
|
|
||||||
|
|
@ -229,6 +229,7 @@ const smallBanner = ref(false);
|
||||||
|
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
v-if="useToggle"
|
v-if="useToggle"
|
||||||
|
:disable="readonly"
|
||||||
two-way
|
two-way
|
||||||
:model-value="toggleStatus !== 'INACTIVE'"
|
:model-value="toggleStatus !== 'INACTIVE'"
|
||||||
@click="$emit('update:toggleStatus', toggleStatus)"
|
@click="$emit('update:toggleStatus', toggleStatus)"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { BranchWithChildren } from 'stores/branch/types';
|
import { BranchWithChildren } from 'stores/branch/types';
|
||||||
import KebabAction from './shared/KebabAction.vue';
|
import KebabAction from './shared/KebabAction.vue';
|
||||||
import { isRoleInclude } from 'stores/utils';
|
|
||||||
|
|
||||||
const nodes = defineModel<(any | BranchWithChildren)[]>('nodes', {
|
const nodes = defineModel<(any | BranchWithChildren)[]>('nodes', {
|
||||||
default: [],
|
default: [],
|
||||||
|
|
@ -17,6 +16,7 @@ withDefaults(
|
||||||
labelKey?: string;
|
labelKey?: string;
|
||||||
childrenKey: string;
|
childrenKey: string;
|
||||||
action?: boolean;
|
action?: boolean;
|
||||||
|
hideCreate?: boolean;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
color: 'transparent',
|
color: 'transparent',
|
||||||
|
|
@ -96,7 +96,9 @@ defineEmits<{
|
||||||
expandedTree[expandedTree.length - 1] === node.id,
|
expandedTree[expandedTree.length - 1] === node.id,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
{{ node.name }}
|
{{
|
||||||
|
$i18n.locale === 'eng' ? node.nameEN || node.name : node.name
|
||||||
|
}}
|
||||||
</span>
|
</span>
|
||||||
<span class="app-text-muted text-caption ellipsis">
|
<span class="app-text-muted text-caption ellipsis">
|
||||||
{{ node.code }}
|
{{ node.code }}
|
||||||
|
|
@ -120,11 +122,7 @@ defineEmits<{
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="
|
v-if="node.isHeadOffice && typeTree === 'branch' && !hideCreate"
|
||||||
node.isHeadOffice &&
|
|
||||||
typeTree === 'branch' &&
|
|
||||||
isRoleInclude(['head_of_admin', 'admin', 'system'])
|
|
||||||
"
|
|
||||||
:id="`create-sub-branch-btn-${node.name}`"
|
:id="`create-sub-branch-btn-${node.name}`"
|
||||||
@click.stop="$emit('create', node)"
|
@click.stop="$emit('create', node)"
|
||||||
icon="mdi-file-plus-outline"
|
icon="mdi-file-plus-outline"
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ defineEmits<{
|
||||||
(e: 'click', v: MouseEvent): void;
|
(e: 'click', v: MouseEvent): void;
|
||||||
}>();
|
}>();
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
id?: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
color: string;
|
color: string;
|
||||||
iconOnly?: boolean;
|
iconOnly?: boolean;
|
||||||
|
|
@ -18,6 +19,7 @@ defineProps<{
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<button
|
<button
|
||||||
|
:id="id"
|
||||||
@click="(e) => $emit('click', e)"
|
@click="(e) => $emit('click', e)"
|
||||||
class="main-btn"
|
class="main-btn"
|
||||||
:class="{
|
:class="{
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ defineProps<{
|
||||||
outlined?: boolean;
|
outlined?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
dark?: boolean;
|
dark?: boolean;
|
||||||
|
color?: string;
|
||||||
|
|
||||||
label?: string;
|
label?: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
|
|
@ -23,7 +24,7 @@ defineProps<{
|
||||||
@click="(e) => $emit('click', e)"
|
@click="(e) => $emit('click', e)"
|
||||||
v-bind="{ ...$props, ...$attrs }"
|
v-bind="{ ...$props, ...$attrs }"
|
||||||
:icon="icon || 'mdi-content-save-outline'"
|
:icon="icon || 'mdi-content-save-outline'"
|
||||||
color="207 96% 32%"
|
:color="color || '207 96% 32%'"
|
||||||
:title="iconOnly ? $t('general.save') : undefined"
|
:title="iconOnly ? $t('general.save') : undefined"
|
||||||
>
|
>
|
||||||
{{ label || $t('general.save') }}
|
{{ label || $t('general.save') }}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import { formatAddress } from 'src/utils/address';
|
||||||
import useOptionStore from 'stores/options';
|
import useOptionStore from 'stores/options';
|
||||||
|
|
||||||
const optionStore = useOptionStore();
|
const optionStore = useOptionStore();
|
||||||
defineProps<{
|
const props = defineProps<{
|
||||||
title?: string;
|
title?: string;
|
||||||
addressTitle?: string;
|
addressTitle?: string;
|
||||||
addressTitleEN?: string;
|
addressTitleEN?: string;
|
||||||
|
|
@ -30,6 +30,7 @@ defineProps<{
|
||||||
|
|
||||||
useEmployment?: boolean;
|
useEmployment?: boolean;
|
||||||
useWorkPlace?: boolean;
|
useWorkPlace?: boolean;
|
||||||
|
useForeignAddress?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const addressStore = useAddressStore();
|
const addressStore = useAddressStore();
|
||||||
|
|
@ -57,6 +58,25 @@ const subDistrictId = defineModel<string | null | undefined>('subDistrictId');
|
||||||
const zipCode = defineModel<string | null | undefined>('zipCode');
|
const zipCode = defineModel<string | null | undefined>('zipCode');
|
||||||
const sameWithEmployer = defineModel<boolean>('sameWithEmployer');
|
const sameWithEmployer = defineModel<boolean>('sameWithEmployer');
|
||||||
|
|
||||||
|
const provinceTextEN = defineModel<string | null | undefined>(
|
||||||
|
'provinceTextEn',
|
||||||
|
{
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const districtTextEN = defineModel<string | null | undefined>(
|
||||||
|
'districtTextEn',
|
||||||
|
{
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const subDistrictTextEN = defineModel<string | null | undefined>(
|
||||||
|
'subDistrictTextEn',
|
||||||
|
{
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const homeCode = defineModel<string | null | undefined>('homeCode');
|
const homeCode = defineModel<string | null | undefined>('homeCode');
|
||||||
const employmentOffice = defineModel<string | null | undefined>(
|
const employmentOffice = defineModel<string | null | undefined>(
|
||||||
'employmentOffice',
|
'employmentOffice',
|
||||||
|
|
@ -64,6 +84,7 @@ const employmentOffice = defineModel<string | null | undefined>(
|
||||||
const employmentOfficeEN = defineModel<string | null | undefined>(
|
const employmentOfficeEN = defineModel<string | null | undefined>(
|
||||||
'employmentOfficeEn',
|
'employmentOfficeEn',
|
||||||
);
|
);
|
||||||
|
const addressForeign = defineModel<boolean>('addressForeign');
|
||||||
|
|
||||||
const addrOptions = reactive<{
|
const addrOptions = reactive<{
|
||||||
provinceOps: Province[];
|
provinceOps: Province[];
|
||||||
|
|
@ -78,14 +99,18 @@ const addrOptions = reactive<{
|
||||||
const area = ref<Office[]>([]);
|
const area = ref<Office[]>([]);
|
||||||
|
|
||||||
const fullAddress = computed(() => {
|
const fullAddress = computed(() => {
|
||||||
const province = provinceOptions.value.find((v) => v.id === provinceId.value);
|
const province = addressForeign.value
|
||||||
const district = districtOptions.value.find((v) => v.id === districtId.value);
|
? { id: '1', name: provinceId.value }
|
||||||
const sDistrict = subDistrictOptions.value.find(
|
: provinceOptions.value.find((v) => v.id === provinceId.value);
|
||||||
(v) => v.id === subDistrictId.value,
|
const district = addressForeign.value
|
||||||
);
|
? { id: '1', name: districtId.value }
|
||||||
|
: districtOptions.value.find((v) => v.id === districtId.value);
|
||||||
|
const sDistrict = addressForeign.value
|
||||||
|
? { id: '1', name: subDistrictId.value }
|
||||||
|
: subDistrictOptions.value.find((v) => v.id === subDistrictId.value);
|
||||||
|
|
||||||
if (province && district && sDistrict) {
|
if (province?.name && district?.name && sDistrict?.name) {
|
||||||
const fullAddress = formatAddress({
|
const fullAddressText = formatAddress({
|
||||||
address: address.value,
|
address: address.value,
|
||||||
addressEN: addressEN.value,
|
addressEN: addressEN.value,
|
||||||
moo: moo.value ? moo.value : '',
|
moo: moo.value ? moo.value : '',
|
||||||
|
|
@ -97,21 +122,26 @@ const fullAddress = computed(() => {
|
||||||
province: province as unknown as Province,
|
province: province as unknown as Province,
|
||||||
district: district as unknown as District,
|
district: district as unknown as District,
|
||||||
subDistrict: sDistrict as unknown as SubDistrict,
|
subDistrict: sDistrict as unknown as SubDistrict,
|
||||||
|
zipCode: addressForeign.value ? zipCode.value || ' ' : undefined,
|
||||||
});
|
});
|
||||||
return fullAddress;
|
return fullAddressText;
|
||||||
}
|
}
|
||||||
return '-';
|
return '-';
|
||||||
});
|
});
|
||||||
|
|
||||||
const fullAddressEN = computed(() => {
|
const fullAddressEN = computed(() => {
|
||||||
const province = provinceOptions.value.find((v) => v.id === provinceId.value);
|
const province = addressForeign.value
|
||||||
const district = districtOptions.value.find((v) => v.id === districtId.value);
|
? { nameEN: provinceTextEN.value }
|
||||||
const sDistrict = subDistrictOptions.value.find(
|
: provinceOptions.value.find((v) => v.id === provinceId.value);
|
||||||
(v) => v.id === subDistrictId.value,
|
const district = addressForeign.value
|
||||||
);
|
? { nameEN: districtTextEN.value }
|
||||||
|
: districtOptions.value.find((v) => v.id === districtId.value);
|
||||||
|
const sDistrict = addressForeign.value
|
||||||
|
? { nameEN: subDistrictTextEN.value }
|
||||||
|
: subDistrictOptions.value.find((v) => v.id === subDistrictId.value);
|
||||||
|
|
||||||
if (province && district && sDistrict) {
|
if (province?.nameEN && district?.nameEN && sDistrict?.nameEN) {
|
||||||
const fullAddress = formatAddress({
|
const fullAddressText = formatAddress({
|
||||||
address: address.value,
|
address: address.value,
|
||||||
addressEN: addressEN.value,
|
addressEN: addressEN.value,
|
||||||
moo: moo.value ? moo.value : '',
|
moo: moo.value ? moo.value : '',
|
||||||
|
|
@ -124,8 +154,9 @@ const fullAddressEN = computed(() => {
|
||||||
district: district as unknown as District,
|
district: district as unknown as District,
|
||||||
subDistrict: sDistrict as unknown as SubDistrict,
|
subDistrict: sDistrict as unknown as SubDistrict,
|
||||||
en: true,
|
en: true,
|
||||||
|
zipCode: addressForeign.value ? zipCode.value || ' ' : undefined,
|
||||||
});
|
});
|
||||||
return fullAddress;
|
return fullAddressText;
|
||||||
}
|
}
|
||||||
return '-';
|
return '-';
|
||||||
});
|
});
|
||||||
|
|
@ -149,7 +180,7 @@ async function fetchProvince() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchDistrict() {
|
async function fetchDistrict() {
|
||||||
if (!provinceId.value) return;
|
if (!provinceId.value || addressForeign.value) return;
|
||||||
|
|
||||||
const result = await addressStore.fetchDistrictByProvinceId(provinceId.value);
|
const result = await addressStore.fetchDistrictByProvinceId(provinceId.value);
|
||||||
if (result) addrOptions.districtOps = result;
|
if (result) addrOptions.districtOps = result;
|
||||||
|
|
@ -168,7 +199,7 @@ async function fetchDistrict() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchSubDistrict() {
|
async function fetchSubDistrict() {
|
||||||
if (!districtId.value) return;
|
if (!districtId.value || addressForeign.value) return;
|
||||||
const result = await addressStore.fetchSubDistrictByProvinceId(
|
const result = await addressStore.fetchSubDistrictByProvinceId(
|
||||||
districtId.value,
|
districtId.value,
|
||||||
);
|
);
|
||||||
|
|
@ -255,6 +286,16 @@ onMounted(async () => {
|
||||||
await fetchSubDistrict();
|
await fetchSubDistrict();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function clearAddress() {
|
||||||
|
provinceId.value = null;
|
||||||
|
districtId.value = null;
|
||||||
|
subDistrictId.value = null;
|
||||||
|
provinceTextEN.value = null;
|
||||||
|
districtTextEN.value = null;
|
||||||
|
subDistrictTextEN.value = null;
|
||||||
|
zipCode.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
watch(provinceId, fetchDistrict);
|
watch(provinceId, fetchDistrict);
|
||||||
watch(districtId, fetchSubDistrict);
|
watch(districtId, fetchSubDistrict);
|
||||||
|
|
||||||
|
|
@ -313,6 +354,15 @@ watchEffect(async () => {
|
||||||
{{ $t('customerEmployee.form.addressCustom') }}
|
{{ $t('customerEmployee.form.addressCustom') }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="useForeignAddress" class="text-caption q-ml-md app-text-muted">
|
||||||
|
<q-checkbox
|
||||||
|
size="xs"
|
||||||
|
v-model="addressForeign"
|
||||||
|
@update:model-value="clearAddress"
|
||||||
|
/>
|
||||||
|
{{ $t('personnel.form.addressForeign') }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12 row q-col-gutter-y-md">
|
<div class="col-12 row q-col-gutter-y-md">
|
||||||
|
|
@ -449,7 +499,24 @@ watchEffect(async () => {
|
||||||
(v) => (typeof v === 'string' ? (street = v) : '')
|
(v) => (typeof v === 'string' ? (street = v) : '')
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
<q-input
|
||||||
|
v-if="addressForeign"
|
||||||
|
outlined
|
||||||
|
hide-bottom-space
|
||||||
|
class="col-md-3 col-6"
|
||||||
|
v-model="provinceId"
|
||||||
|
:dense="dense"
|
||||||
|
:label="$t('form.province')"
|
||||||
|
:readonly="readonly || sameWithEmployer"
|
||||||
|
:for="`${prefixId}-${indexId !== undefined ? `input-province-${indexId}` : 'input-province'}`"
|
||||||
|
:rules="
|
||||||
|
disabledRule
|
||||||
|
? []
|
||||||
|
: [(val) => (val && val.length > 0) || $t('form.error.required')]
|
||||||
|
"
|
||||||
|
/>
|
||||||
<q-select
|
<q-select
|
||||||
|
v-else
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
outlined
|
outlined
|
||||||
clearable
|
clearable
|
||||||
|
|
@ -493,7 +560,24 @@ watchEffect(async () => {
|
||||||
</template>
|
</template>
|
||||||
</q-select>
|
</q-select>
|
||||||
|
|
||||||
|
<q-input
|
||||||
|
v-if="addressForeign"
|
||||||
|
outlined
|
||||||
|
hide-bottom-space
|
||||||
|
class="col-md-3 col-6"
|
||||||
|
v-model="districtId"
|
||||||
|
:dense="dense"
|
||||||
|
:label="$t('form.district')"
|
||||||
|
:readonly="readonly || sameWithEmployer"
|
||||||
|
:for="`${prefixId}-${indexId !== undefined ? `input-district-${indexId}` : 'input-district'}`"
|
||||||
|
:rules="
|
||||||
|
disabledRule
|
||||||
|
? []
|
||||||
|
: [(val) => (val && val.length > 0) || $t('form.error.required')]
|
||||||
|
"
|
||||||
|
/>
|
||||||
<q-select
|
<q-select
|
||||||
|
v-else
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
outlined
|
outlined
|
||||||
clearable
|
clearable
|
||||||
|
|
@ -536,7 +620,25 @@ watchEffect(async () => {
|
||||||
</q-item>
|
</q-item>
|
||||||
</template>
|
</template>
|
||||||
</q-select>
|
</q-select>
|
||||||
|
|
||||||
|
<q-input
|
||||||
|
v-if="addressForeign"
|
||||||
|
outlined
|
||||||
|
hide-bottom-space
|
||||||
|
class="col-md-3 col-6"
|
||||||
|
v-model="subDistrictId"
|
||||||
|
:dense="dense"
|
||||||
|
:label="$t('form.district')"
|
||||||
|
:readonly="readonly || sameWithEmployer"
|
||||||
|
:for="`${prefixId}-${indexId !== undefined ? `input-sub-district-${indexId}` : 'input-sub-district'}`"
|
||||||
|
:rules="
|
||||||
|
disabledRule
|
||||||
|
? []
|
||||||
|
: [(val) => (val && val.length > 0) || $t('form.error.required')]
|
||||||
|
"
|
||||||
|
/>
|
||||||
<q-select
|
<q-select
|
||||||
|
v-else
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
outlined
|
outlined
|
||||||
clearable
|
clearable
|
||||||
|
|
@ -580,17 +682,27 @@ watchEffect(async () => {
|
||||||
</template>
|
</template>
|
||||||
</q-select>
|
</q-select>
|
||||||
<q-input
|
<q-input
|
||||||
|
:key="Number(addressForeign)"
|
||||||
|
hide-bottom-space
|
||||||
:for="`${prefixId}-${indexId !== undefined ? `input-zip-code-${indexId}` : 'input-zip-code'}`"
|
:for="`${prefixId}-${indexId !== undefined ? `input-zip-code-${indexId}` : 'input-zip-code'}`"
|
||||||
:dense="dense"
|
:dense="dense"
|
||||||
outlined
|
outlined
|
||||||
:disable="!readonly && !sameWithEmployer"
|
:disable="!addressForeign && !readonly && !sameWithEmployer"
|
||||||
readonly
|
:readonly="!addressForeign || readonly"
|
||||||
:label="$t('form.zipCode')"
|
:label="$t('form.zipCode')"
|
||||||
class="col-md-3 col-6"
|
class="col-md-3 col-6"
|
||||||
:model-value="
|
:model-value="
|
||||||
addrOptions.subDistrictOps
|
!addressForeign
|
||||||
?.filter((x) => x.id === subDistrictId)
|
? (addrOptions.subDistrictOps
|
||||||
.map((x) => x.zipCode)[0] ?? ''
|
?.filter((x) => x.id === subDistrictId)
|
||||||
|
.map((x) => x.zipCode)[0] ?? '')
|
||||||
|
: zipCode
|
||||||
|
"
|
||||||
|
@update:model-value="(v) => (zipCode = v.toString())"
|
||||||
|
:rules="
|
||||||
|
!addressForeign
|
||||||
|
? []
|
||||||
|
: [(val) => (val && val.length > 0) || $t('form.error.required')]
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<q-input
|
<q-input
|
||||||
|
|
@ -689,7 +801,24 @@ watchEffect(async () => {
|
||||||
(v) => (typeof v === 'string' ? (streetEN = v) : '')
|
(v) => (typeof v === 'string' ? (streetEN = v) : '')
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
<q-input
|
||||||
|
v-if="addressForeign"
|
||||||
|
outlined
|
||||||
|
hide-bottom-space
|
||||||
|
class="col-md-3 col-6"
|
||||||
|
v-model="provinceTextEN"
|
||||||
|
:dense="dense"
|
||||||
|
label="Province"
|
||||||
|
:readonly="readonly || sameWithEmployer"
|
||||||
|
:for="`${prefixId}-${indexId !== undefined ? `input-province-en-${indexId}` : 'input-province-en'}`"
|
||||||
|
:rules="
|
||||||
|
disabledRule
|
||||||
|
? []
|
||||||
|
: [(val) => (val && val.length > 0) || $t('form.error.required')]
|
||||||
|
"
|
||||||
|
/>
|
||||||
<q-select
|
<q-select
|
||||||
|
v-else
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
outlined
|
outlined
|
||||||
clearable
|
clearable
|
||||||
|
|
@ -732,7 +861,25 @@ watchEffect(async () => {
|
||||||
</q-item>
|
</q-item>
|
||||||
</template>
|
</template>
|
||||||
</q-select>
|
</q-select>
|
||||||
|
|
||||||
|
<q-input
|
||||||
|
v-if="addressForeign"
|
||||||
|
outlined
|
||||||
|
hide-bottom-space
|
||||||
|
class="col-md-3 col-6"
|
||||||
|
v-model="districtTextEN"
|
||||||
|
:dense="dense"
|
||||||
|
label="District"
|
||||||
|
:readonly="readonly || sameWithEmployer"
|
||||||
|
:for="`${prefixId}-${indexId !== undefined ? `input-district-en-${indexId}` : 'input-district-en'}`"
|
||||||
|
:rules="
|
||||||
|
disabledRule
|
||||||
|
? []
|
||||||
|
: [(val) => (val && val.length > 0) || $t('form.error.required')]
|
||||||
|
"
|
||||||
|
/>
|
||||||
<q-select
|
<q-select
|
||||||
|
v-else
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
outlined
|
outlined
|
||||||
clearable
|
clearable
|
||||||
|
|
@ -775,7 +922,25 @@ watchEffect(async () => {
|
||||||
</q-item>
|
</q-item>
|
||||||
</template>
|
</template>
|
||||||
</q-select>
|
</q-select>
|
||||||
|
|
||||||
|
<q-input
|
||||||
|
v-if="addressForeign"
|
||||||
|
outlined
|
||||||
|
hide-bottom-space
|
||||||
|
class="col-md-3 col-6"
|
||||||
|
v-model="subDistrictTextEN"
|
||||||
|
:dense="dense"
|
||||||
|
label="Sub-District"
|
||||||
|
:readonly="readonly || sameWithEmployer"
|
||||||
|
:for="`${prefixId}-${indexId !== undefined ? `input-sub-district-en-${indexId}` : 'input-sub-district-en'}`"
|
||||||
|
:rules="
|
||||||
|
disabledRule
|
||||||
|
? []
|
||||||
|
: [(val) => (val && val.length > 0) || $t('form.error.required')]
|
||||||
|
"
|
||||||
|
/>
|
||||||
<q-select
|
<q-select
|
||||||
|
v-else
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
outlined
|
outlined
|
||||||
clearable
|
clearable
|
||||||
|
|
@ -819,19 +984,28 @@ watchEffect(async () => {
|
||||||
</template>
|
</template>
|
||||||
</q-select>
|
</q-select>
|
||||||
<q-input
|
<q-input
|
||||||
|
:key="Number(addressForeign)"
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
:for="`${prefixId}-${indexId !== undefined ? `input-zip-code-${indexId}` : 'input-zip-code'}`"
|
:for="`${prefixId}-${indexId !== undefined ? `input-zip-code-${indexId}` : 'input-zip-code'}`"
|
||||||
:dense="dense"
|
:dense="dense"
|
||||||
outlined
|
outlined
|
||||||
readonly
|
:readonly="!addressForeign || readonly"
|
||||||
:disable="!readonly && !sameWithEmployer"
|
:disable="!addressForeign && !readonly && !sameWithEmployer"
|
||||||
zip="zip-en"
|
zip="zip-en"
|
||||||
label="Zip Code"
|
label="Zip Code"
|
||||||
class="col-md-3 col-6"
|
class="col-md-3 col-6"
|
||||||
:model-value="
|
:model-value="
|
||||||
addrOptions.subDistrictOps
|
!addressForeign
|
||||||
?.filter((x) => x.id === subDistrictId)
|
? (addrOptions.subDistrictOps
|
||||||
.map((x) => x.zipCode)[0] ?? ''
|
?.filter((x) => x.id === subDistrictId)
|
||||||
|
.map((x) => x.zipCode)[0] ?? '')
|
||||||
|
: zipCode
|
||||||
|
"
|
||||||
|
@update:model-value="(v) => (zipCode = v.toString())"
|
||||||
|
:rules="
|
||||||
|
!addressForeign
|
||||||
|
? []
|
||||||
|
: [(val) => (val && val.length > 0) || $t('form.error.required')]
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<q-input
|
<q-input
|
||||||
|
|
|
||||||
|
|
@ -16,3 +16,4 @@ export { default as SideMenu } from './SideMenu.vue';
|
||||||
export { default as StatCardComponent } from './StatCardComponent.vue';
|
export { default as StatCardComponent } from './StatCardComponent.vue';
|
||||||
export { default as TooltipComponent } from './TooltipComponent.vue';
|
export { default as TooltipComponent } from './TooltipComponent.vue';
|
||||||
export { default as TreeComponent } from './TreeComponent.vue';
|
export { default as TreeComponent } from './TreeComponent.vue';
|
||||||
|
export { default as PaginationPageSize } from './PaginationPageSize.vue';
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ watch(
|
||||||
:persistent="isDateSelect"
|
:persistent="isDateSelect"
|
||||||
>
|
>
|
||||||
<div class="q-pa-sm">
|
<div class="q-pa-sm">
|
||||||
|
<slot name="prepend"></slot>
|
||||||
<div class="text-weight-medium">
|
<div class="text-weight-medium">
|
||||||
{{ $t('general.advanceSearch') }}
|
{{ $t('general.advanceSearch') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ defineProps<{
|
||||||
history?: boolean;
|
history?: boolean;
|
||||||
prefixId?: string;
|
prefixId?: string;
|
||||||
separateEnter?: boolean;
|
separateEnter?: boolean;
|
||||||
|
hideAction?: boolean;
|
||||||
|
hideDelete?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
|
|
@ -76,8 +78,10 @@ defineEmits<{
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<KebabAction
|
<KebabAction
|
||||||
|
v-if="!hideAction"
|
||||||
:id-name="prefixId"
|
:id-name="prefixId"
|
||||||
:status="disabled ? 'INACTIVE' : 'ACTIVE'"
|
:status="disabled ? 'INACTIVE' : 'ACTIVE'"
|
||||||
|
:hide-delete="hideDelete"
|
||||||
@view="
|
@view="
|
||||||
separateEnter
|
separateEnter
|
||||||
? $emit('viewCard', 'INFO')
|
? $emit('viewCard', 'INFO')
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ let defaultFilter: (
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
prefix?: string;
|
||||||
id?: string;
|
id?: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
option: T[];
|
option: T[];
|
||||||
|
|
@ -71,6 +72,7 @@ watch(
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<q-select
|
<q-select
|
||||||
|
:id="id"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
outlined
|
outlined
|
||||||
:clearable
|
:clearable
|
||||||
|
|
|
||||||
|
|
@ -75,9 +75,9 @@ function setDefaultValue() {
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<SelectInput
|
<SelectInput
|
||||||
for="select-hq-id"
|
|
||||||
v-model="value"
|
v-model="value"
|
||||||
incremental
|
incremental
|
||||||
|
id="select-hq-id"
|
||||||
:label
|
:label
|
||||||
:placeholder
|
:placeholder
|
||||||
:readonly
|
:readonly
|
||||||
|
|
|
||||||
213
src/components/shared/select/SelectBusinessType.vue
Normal file
|
|
@ -0,0 +1,213 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
|
||||||
|
import { createSelect, SelectProps } from './select';
|
||||||
|
import SelectInput from '../SelectInput.vue';
|
||||||
|
|
||||||
|
import { BusinessType } from 'src/stores/business-type/types';
|
||||||
|
|
||||||
|
import useStore from 'src/stores/business-type';
|
||||||
|
|
||||||
|
type SelectOption = BusinessType;
|
||||||
|
|
||||||
|
const value = defineModel<string | null | undefined>('value', {
|
||||||
|
required: true,
|
||||||
|
});
|
||||||
|
const valueOption = defineModel<SelectOption>('valueOption', {
|
||||||
|
required: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectOptions = ref<SelectOption[]>([]);
|
||||||
|
|
||||||
|
const { fetchList: getList, fetchById: getById } = useStore();
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
(e: 'create'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
type ExclusiveProps = {
|
||||||
|
lang?: string;
|
||||||
|
codeOnly?: boolean;
|
||||||
|
selectFirstValue?: boolean;
|
||||||
|
branchVirtual?: boolean;
|
||||||
|
checkRole?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const props = defineProps<SelectProps<typeof getList> & ExclusiveProps>();
|
||||||
|
|
||||||
|
const { getOptions, setFirstValue, getSelectedOption, filter } =
|
||||||
|
createSelect<SelectOption>(
|
||||||
|
{
|
||||||
|
value,
|
||||||
|
valueOption,
|
||||||
|
selectOptions,
|
||||||
|
getList: async (query) => {
|
||||||
|
const ret = await getList({
|
||||||
|
query,
|
||||||
|
...props.params,
|
||||||
|
pageSize: 99999,
|
||||||
|
});
|
||||||
|
if (ret) return ret.result;
|
||||||
|
},
|
||||||
|
getByValue: async (id) => {
|
||||||
|
const ret = await getById(id);
|
||||||
|
if (ret) return ret;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ valueField: 'id' },
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await getOptions();
|
||||||
|
|
||||||
|
if (props.autoSelectOnSingle && selectOptions.value.length === 1) {
|
||||||
|
setFirstValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.selectFirstValue) {
|
||||||
|
setDefaultValue();
|
||||||
|
} else await getSelectedOption();
|
||||||
|
});
|
||||||
|
|
||||||
|
function setDefaultValue() {
|
||||||
|
setFirstValue();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<SelectInput
|
||||||
|
v-model="value"
|
||||||
|
incremental
|
||||||
|
option-value="id"
|
||||||
|
:label="label || $t('menu.manage.businessType')"
|
||||||
|
:placeholder
|
||||||
|
:readonly
|
||||||
|
:disable="disabled"
|
||||||
|
:option="selectOptions"
|
||||||
|
:hide-selected="false"
|
||||||
|
:fill-input="false"
|
||||||
|
:rules="[
|
||||||
|
(v: string) => !props.required || !!v || $t('form.error.required'),
|
||||||
|
]"
|
||||||
|
@filter="filter"
|
||||||
|
>
|
||||||
|
<template #selected-item="{ opt }">
|
||||||
|
{{ (lang ?? $i18n.locale) !== 'eng' ? opt.name : opt.nameEN }}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #no-option v-if="creatable">
|
||||||
|
<q-item
|
||||||
|
:disable="creatableDisabled"
|
||||||
|
clickable
|
||||||
|
v-close-popup
|
||||||
|
@click.stop="$emit('create')"
|
||||||
|
>
|
||||||
|
<q-item-section>
|
||||||
|
<span class="row items-center">
|
||||||
|
<q-icon
|
||||||
|
name="mdi-plus-circle-outline"
|
||||||
|
class="q-mr-sm"
|
||||||
|
style="color: hsl(var(--positive-bg))"
|
||||||
|
/>
|
||||||
|
<b>
|
||||||
|
{{ $t('general.add', { text: $t('businessType.title') }) }}
|
||||||
|
</b>
|
||||||
|
<span
|
||||||
|
v-if="creatableDisabled && creatableDisabledText"
|
||||||
|
class="app-text-muted q-pl-xs"
|
||||||
|
style="font-size: 80%"
|
||||||
|
>
|
||||||
|
{{ creatableDisabledText }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-separator class="q-mx-sm" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #before-options v-if="creatable">
|
||||||
|
<q-item
|
||||||
|
:disable="creatableDisabled"
|
||||||
|
clickable
|
||||||
|
v-close-popup
|
||||||
|
@click.stop="$emit('create')"
|
||||||
|
for="select-biz-type-add-new"
|
||||||
|
id="select-biz-type-add-new"
|
||||||
|
>
|
||||||
|
<q-item-section>
|
||||||
|
<span class="row items-center">
|
||||||
|
<q-icon
|
||||||
|
name="mdi-plus-circle-outline"
|
||||||
|
class="q-mr-sm"
|
||||||
|
style="color: hsl(var(--positive-bg))"
|
||||||
|
/>
|
||||||
|
<b>
|
||||||
|
{{ $t('general.add', { text: $t('businessType.title') }) }}
|
||||||
|
</b>
|
||||||
|
<span
|
||||||
|
v-if="creatableDisabled && creatableDisabledText"
|
||||||
|
class="app-text-muted q-pl-xs"
|
||||||
|
style="font-size: 80%"
|
||||||
|
>
|
||||||
|
{{ creatableDisabledText }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-separator class="q-mx-sm" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #before-options v-if="creatable">
|
||||||
|
<q-item
|
||||||
|
:disable="creatableDisabled"
|
||||||
|
clickable
|
||||||
|
v-close-popup
|
||||||
|
@click.stop="$emit('create')"
|
||||||
|
for="select-business-type-add-new"
|
||||||
|
id="select-business-type-add-new"
|
||||||
|
>
|
||||||
|
<q-item-section>
|
||||||
|
<span class="row items-center">
|
||||||
|
<q-icon
|
||||||
|
name="mdi-plus-circle-outline"
|
||||||
|
class="q-mr-sm"
|
||||||
|
style="color: hsl(var(--positive-bg))"
|
||||||
|
/>
|
||||||
|
<b>
|
||||||
|
{{ $t('general.add', { text: $t('menu.manage.businessType') }) }}
|
||||||
|
</b>
|
||||||
|
<span
|
||||||
|
v-if="creatableDisabled && creatableDisabledText"
|
||||||
|
class="app-text-muted q-pl-xs"
|
||||||
|
style="font-size: 80%"
|
||||||
|
>
|
||||||
|
{{ creatableDisabledText }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-separator class="q-mx-sm" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #option="{ opt, scope }">
|
||||||
|
<q-item v-bind="scope.itemProps">
|
||||||
|
<span class="row items-center">
|
||||||
|
{{ (lang ?? $i18n.locale) !== 'eng' ? opt.name : opt.nameEN }}
|
||||||
|
</span>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-separator class="q-mx-sm" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #append v-if="clearable">
|
||||||
|
<q-icon
|
||||||
|
v-if="!readonly && value"
|
||||||
|
name="mdi-close-circle"
|
||||||
|
@click.stop="value = ''"
|
||||||
|
class="cursor-pointer clear-btn"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</SelectInput>
|
||||||
|
</template>
|
||||||
|
|
@ -30,6 +30,7 @@ defineEmits<{
|
||||||
type ExclusiveProps = {
|
type ExclusiveProps = {
|
||||||
simple?: boolean;
|
simple?: boolean;
|
||||||
simpleBranchNo?: boolean;
|
simpleBranchNo?: boolean;
|
||||||
|
selectFirstValue?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const props = defineProps<SelectProps<typeof getList> & ExclusiveProps>();
|
const props = defineProps<SelectProps<typeof getList> & ExclusiveProps>();
|
||||||
|
|
@ -64,10 +65,14 @@ onMounted(async () => {
|
||||||
setFirstValue();
|
setFirstValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
await getSelectedOption();
|
if (props.selectFirstValue) {
|
||||||
|
setDefaultValue();
|
||||||
valueOption.value = selectOptions.value.find((v) => v.id === value.value);
|
} else await getSelectedOption();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function setDefaultValue() {
|
||||||
|
setFirstValue();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<SelectInput
|
<SelectInput
|
||||||
|
|
@ -160,11 +165,9 @@ onMounted(async () => {
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #option="{ opt, scope }">
|
<template #option="{ opt, scope }">
|
||||||
<q-item @click="valueOption = opt" v-bind="scope.itemProps">
|
<q-item v-bind="scope.itemProps" class="q-mx-sm bodrder">
|
||||||
<SelectCustomerItem :data="opt" :simple :simple-branch-no />
|
<SelectCustomerItem :data="opt" :simple :simple-branch-no />
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
<q-separator class="q-mx-sm" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #append v-if="clearable">
|
<template #append v-if="clearable">
|
||||||
|
|
@ -177,3 +180,11 @@ onMounted(async () => {
|
||||||
</template>
|
</template>
|
||||||
</SelectInput>
|
</SelectInput>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.bodrder {
|
||||||
|
border-bottom: solid;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-color: var(--border-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ const { getQuotationList: getList, getQuotation: getById } = useStore();
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
(e: 'create'): void;
|
(e: 'create'): void;
|
||||||
|
(e: 'selected', value: SelectOption): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
type ExclusiveProps = {
|
type ExclusiveProps = {
|
||||||
|
|
@ -117,6 +118,14 @@ function setDefaultValue() {
|
||||||
(v: string) => !props.required || !!v || $t('form.error.required'),
|
(v: string) => !props.required || !!v || $t('form.error.required'),
|
||||||
]"
|
]"
|
||||||
@filter="filter"
|
@filter="filter"
|
||||||
|
@update:model-value="
|
||||||
|
(v) => {
|
||||||
|
$emit(
|
||||||
|
'selected',
|
||||||
|
selectOptions.find((opt) => opt.id === v),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<template #append v-if="clearable">
|
<template #append v-if="clearable">
|
||||||
<q-icon
|
<q-icon
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ defineEmits<{
|
||||||
|
|
||||||
type ExclusiveProps = {
|
type ExclusiveProps = {
|
||||||
selectFirstValue?: boolean;
|
selectFirstValue?: boolean;
|
||||||
|
prefix?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const props = defineProps<SelectProps<typeof getList> & ExclusiveProps>();
|
const props = defineProps<SelectProps<typeof getList> & ExclusiveProps>();
|
||||||
|
|
@ -71,6 +72,7 @@ function setDefaultValue() {
|
||||||
<SelectInput
|
<SelectInput
|
||||||
v-model="value"
|
v-model="value"
|
||||||
incremental
|
incremental
|
||||||
|
:id="`${prefix || 'nome'}-select-user`"
|
||||||
:label
|
:label
|
||||||
:placeholder
|
:placeholder
|
||||||
:readonly
|
:readonly
|
||||||
|
|
@ -92,7 +94,9 @@ function setDefaultValue() {
|
||||||
:hide-selected="false"
|
:hide-selected="false"
|
||||||
:fill-input="false"
|
:fill-input="false"
|
||||||
:rules="
|
:rules="
|
||||||
required ? [(v: string) => !!v || $t('form.error.required')] : undefined
|
required && !readonly
|
||||||
|
? [(v: string) => !!v || $t('form.error.required')]
|
||||||
|
: undefined
|
||||||
"
|
"
|
||||||
@filter="filter"
|
@filter="filter"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,13 @@ export const createSelect = <T extends Record<string, any>>(
|
||||||
let previousSearch = '';
|
let previousSearch = '';
|
||||||
|
|
||||||
watch(value, (v) => {
|
watch(value, (v) => {
|
||||||
if (!v || (cache && cache.find((opt) => opt[valueField] === v))) return;
|
if (!v) return;
|
||||||
|
|
||||||
|
if (cache && cache.find((opt) => opt[valueField] === v)) {
|
||||||
|
valueOption.value = cache.find((opt) => opt[valueField] === v);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
getSelectedOption();
|
getSelectedOption();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -63,15 +69,26 @@ export const createSelect = <T extends Record<string, any>>(
|
||||||
const currentValue = value.value;
|
const currentValue = value.value;
|
||||||
|
|
||||||
if (!currentValue) return;
|
if (!currentValue) return;
|
||||||
if (selectOptions.value.find((v) => v[valueField] === currentValue)) return;
|
|
||||||
if (valueOption.value && valueOption.value[valueField] === currentValue) {
|
if (valueOption.value && valueOption.value[valueField] === currentValue) {
|
||||||
return selectOptions.value.unshift(valueOption.value);
|
selectOptions.value.unshift(valueOption.value);
|
||||||
|
selectOptions.value = selectOptions.value.filter((curr, idx, arr) => {
|
||||||
|
return (
|
||||||
|
arr.findIndex((item) => item[valueField] === curr[valueField]) === idx
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ret = await getByValue(currentValue);
|
const ret = await getByValue(currentValue);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
selectOptions.value.unshift(ret);
|
selectOptions.value.unshift(ret);
|
||||||
|
selectOptions.value = selectOptions.value.filter((curr, idx, arr) => {
|
||||||
|
return (
|
||||||
|
arr.findIndex((item) => item[valueField] === curr[valueField]) === idx
|
||||||
|
);
|
||||||
|
});
|
||||||
valueOption.value = ret;
|
valueOption.value = ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -251,7 +251,10 @@ function selectedIndex(item: any) {
|
||||||
>
|
>
|
||||||
<!-- NOTE: custom column will starts with # -->
|
<!-- NOTE: custom column will starts with # -->
|
||||||
<template v-if="!col.name.startsWith('#')">
|
<template v-if="!col.name.startsWith('#')">
|
||||||
<span>
|
<span v-if="col.name === 'serviceDetail'">
|
||||||
|
{{ props.row.detail.replace(/<\/?[^>]+(>|$)/g, '') || '-' }}
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
{{
|
{{
|
||||||
typeof col.field === 'string'
|
typeof col.field === 'string'
|
||||||
? props.row[col.field as keyof (Product | Service)]
|
? props.row[col.field as keyof (Product | Service)]
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,7 @@ function selectedIndex(item: Employee) {
|
||||||
<template v-if="col.name === '#check'">
|
<template v-if="col.name === '#check'">
|
||||||
<q-checkbox
|
<q-checkbox
|
||||||
id="select-worker-all"
|
id="select-worker-all"
|
||||||
|
for="select-worker-all"
|
||||||
v-model="props.selected"
|
v-model="props.selected"
|
||||||
@update:model-value="(v) => handleUpdate()"
|
@update:model-value="(v) => handleUpdate()"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
@ -200,6 +201,7 @@ function selectedIndex(item: Employee) {
|
||||||
v-model="props.selected"
|
v-model="props.selected"
|
||||||
size="sm"
|
size="sm"
|
||||||
:id="`select-worker-${props.row.firstName}`"
|
:id="`select-worker-${props.row.firstName}`"
|
||||||
|
:for="`select-worker-${props.row.firstName}`"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,7 @@ function formatCode(input: string | undefined, type: 'code' | 'number') {
|
||||||
:label="$t('customer.form.citizenId')"
|
:label="$t('customer.form.citizenId')"
|
||||||
for="input-citizen-id"
|
for="input-citizen-id"
|
||||||
v-model="citizenId"
|
v-model="citizenId"
|
||||||
|
:rules="[(val: string) => !!val || $t('form.error.required')]"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DatePicker
|
<DatePicker
|
||||||
|
|
@ -221,6 +222,7 @@ function formatCode(input: string | undefined, type: 'code' | 'number') {
|
||||||
:label="$t('customer.form.religion')"
|
:label="$t('customer.form.religion')"
|
||||||
for="input-religion"
|
for="input-religion"
|
||||||
v-model="religion"
|
v-model="religion"
|
||||||
|
:rules="[(val: string) => !!val || $t('form.error.required')]"
|
||||||
/>
|
/>
|
||||||
<q-select
|
<q-select
|
||||||
outlined
|
outlined
|
||||||
|
|
@ -305,6 +307,7 @@ function formatCode(input: string | undefined, type: 'code' | 'number') {
|
||||||
:label="$t('customer.form.firstName')"
|
:label="$t('customer.form.firstName')"
|
||||||
for="input-first-name"
|
for="input-first-name"
|
||||||
v-model="firstName"
|
v-model="firstName"
|
||||||
|
:rules="[(val: string) => !!val || $t('form.error.required')]"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-input
|
<q-input
|
||||||
|
|
@ -316,6 +319,7 @@ function formatCode(input: string | undefined, type: 'code' | 'number') {
|
||||||
:label="$t('customer.form.lastName')"
|
:label="$t('customer.form.lastName')"
|
||||||
for="input-last-name"
|
for="input-last-name"
|
||||||
v-model="lastName"
|
v-model="lastName"
|
||||||
|
:rules="[(val: string) => !!val || $t('form.error.required')]"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-input
|
<q-input
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ type Props = {
|
||||||
autoSave?: boolean;
|
autoSave?: boolean;
|
||||||
data?: Data;
|
data?: Data;
|
||||||
hideBtn?: boolean;
|
hideBtn?: boolean;
|
||||||
|
disabledSubmit?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type HandleProps = {
|
type HandleProps = {
|
||||||
|
|
@ -109,6 +110,7 @@ async function change(e: Event) {
|
||||||
hide-delete
|
hide-delete
|
||||||
hide-btn
|
hide-btn
|
||||||
edit
|
edit
|
||||||
|
:disabledSubmit
|
||||||
:title
|
:title
|
||||||
:is-edit
|
:is-edit
|
||||||
:readonly
|
:readonly
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ const currentIndexDropdownList = ref(0);
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
treeFile: { label: string; file: { label: string }[] }[];
|
treeFile?: { label: string; file: { label: string }[] }[];
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
dropdownList?: { label: string; value: string }[];
|
dropdownList?: { label: string; value: string }[];
|
||||||
hideAction?: boolean;
|
hideAction?: boolean;
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,11 @@ 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">
|
<div class="col column q-pl-md">
|
||||||
<span class="ellipsis full-width">
|
<div class="ellipsis full-width" style="max-width: 65vw !important">
|
||||||
{{ name }}
|
{{ name }}
|
||||||
</span>
|
</div>
|
||||||
|
|
||||||
<span class="text-caption app-text-muted-2">
|
<span class="text-caption app-text-muted-2">
|
||||||
{{
|
{{
|
||||||
uploading.loaded
|
uploading.loaded
|
||||||
|
|
@ -79,7 +80,7 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
{{ idle ? `Pending` : progress !== 1 ? `Uploading...` : 'Completed' }}
|
{{ idle ? `Pending` : progress !== 1 ? `Uploading...` : 'Completed' }}
|
||||||
</span>
|
</span>
|
||||||
</article>
|
</div>
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="closeable"
|
v-if="closeable"
|
||||||
icon="mdi-close"
|
icon="mdi-close"
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,9 @@ const props = withDefaults(
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
showTitle?: boolean;
|
showTitle?: boolean;
|
||||||
ocr?: (
|
ocr?: (
|
||||||
group: any,
|
group: string,
|
||||||
file: File,
|
file: File,
|
||||||
) => void | Promise<{
|
) => Promise<{
|
||||||
status: boolean;
|
status: boolean;
|
||||||
group: string;
|
group: string;
|
||||||
meta: { name: string; value: string }[];
|
meta: { name: string; value: string }[];
|
||||||
|
|
@ -123,7 +123,7 @@ async function change(e: Event) {
|
||||||
...obj.value,
|
...obj.value,
|
||||||
{
|
{
|
||||||
_meta: structuredClone(toRaw(selectedMenu.value)._meta || {}),
|
_meta: structuredClone(toRaw(selectedMenu.value)._meta || {}),
|
||||||
group: selectedMenu.value?.value,
|
group: selectedMenu.value?.group,
|
||||||
file: renamedFile,
|
file: renamedFile,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -168,8 +168,8 @@ async function change(e: Event) {
|
||||||
type: map['doc_type'],
|
type: map['doc_type'],
|
||||||
number: map['doc_number'],
|
number: map['doc_number'],
|
||||||
gender: map['sex'],
|
gender: map['sex'],
|
||||||
firstName: map['first_name'],
|
firstName: map['last_name'],
|
||||||
lastName: map['last_name'],
|
lastName: map['first_name'],
|
||||||
issueDate: map['issue_date'],
|
issueDate: map['issue_date'],
|
||||||
expireDate: map['expire_date'],
|
expireDate: map['expire_date'],
|
||||||
issuePlace: map['nationality'],
|
issuePlace: map['nationality'],
|
||||||
|
|
@ -327,7 +327,7 @@ defineEmits<{
|
||||||
:rows="
|
:rows="
|
||||||
obj
|
obj
|
||||||
.filter((v) => {
|
.filter((v) => {
|
||||||
if (!autoSave && v.group !== selectedMenu?.value) {
|
if (!autoSave && v.group !== selectedMenu?.group) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -198,3 +198,10 @@ i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-i
|
||||||
.q-focus-helper {
|
.q-focus-helper {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clear-btn {
|
||||||
|
opacity: 0.6;
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ export default {
|
||||||
save: 'Save',
|
save: 'Save',
|
||||||
open: 'Open',
|
open: 'Open',
|
||||||
close: 'Close',
|
close: 'Close',
|
||||||
edit: 'Edit',
|
edit: 'Edit{text}',
|
||||||
cancel: 'Cancel',
|
cancel: 'Cancel',
|
||||||
back: 'Back',
|
back: 'Back',
|
||||||
undo: 'Undo',
|
undo: 'Undo',
|
||||||
|
|
@ -31,6 +31,7 @@ export default {
|
||||||
displayField: 'Display Fields',
|
displayField: 'Display Fields',
|
||||||
order: 'Order',
|
order: 'Order',
|
||||||
name: '{msg} Name',
|
name: '{msg} Name',
|
||||||
|
nameEN: 'Name (English)',
|
||||||
fullName: 'Full Name',
|
fullName: 'Full Name',
|
||||||
detail: '{msg} Detail',
|
detail: '{msg} Detail',
|
||||||
remark: '{msg} Remark',
|
remark: '{msg} Remark',
|
||||||
|
|
@ -160,6 +161,7 @@ export default {
|
||||||
documentStatus: 'Document Status',
|
documentStatus: 'Document Status',
|
||||||
advanceSearch: 'Advance Search',
|
advanceSearch: 'Advance Search',
|
||||||
totalPeople: '{meg} people',
|
totalPeople: '{meg} people',
|
||||||
|
price: 'Price {price} Baht',
|
||||||
},
|
},
|
||||||
|
|
||||||
menu: {
|
menu: {
|
||||||
|
|
@ -202,12 +204,14 @@ export default {
|
||||||
title: 'Manage',
|
title: 'Manage',
|
||||||
branch: 'Branch',
|
branch: 'Branch',
|
||||||
personnel: 'Personnel',
|
personnel: 'Personnel',
|
||||||
|
group: 'Group',
|
||||||
productService: 'Product and Service',
|
productService: 'Product and Service',
|
||||||
workflow: 'Workflow',
|
workflow: 'Workflow',
|
||||||
property: 'Property',
|
property: 'Property',
|
||||||
customer: 'Customer',
|
customer: 'Customer',
|
||||||
mainData: 'Main Data',
|
mainData: 'Main Data',
|
||||||
agencies: 'Agencies',
|
agencies: 'Agencies',
|
||||||
|
businessType: 'Business Type',
|
||||||
},
|
},
|
||||||
|
|
||||||
sales: {
|
sales: {
|
||||||
|
|
@ -337,7 +341,7 @@ export default {
|
||||||
requireLength: 'Please enter {msg} character',
|
requireLength: 'Please enter {msg} character',
|
||||||
branchNameField: "Only letters, numbers, or the characters . , - ' &.",
|
branchNameField: "Only letters, numbers, or the characters . , - ' &.",
|
||||||
branchNameENField:
|
branchNameENField:
|
||||||
"Only English letters, numbers, or the characters . , - ' &.",
|
"Only English letters, numbers, or the characters . , - ' &. ( )",
|
||||||
passportFormat: 'Please enter the passport number in the correct format.',
|
passportFormat: 'Please enter the passport number in the correct format.',
|
||||||
},
|
},
|
||||||
warning: {
|
warning: {
|
||||||
|
|
@ -456,7 +460,7 @@ export default {
|
||||||
regisNo: 'Registration Number',
|
regisNo: 'Registration Number',
|
||||||
startDate: 'Start Date',
|
startDate: 'Start Date',
|
||||||
retireDate: 'Retire Date',
|
retireDate: 'Retire Date',
|
||||||
responsibleArea: 'Responsibel Area',
|
responsibleArea: 'Responsible Area',
|
||||||
discount: 'Discount Condition',
|
discount: 'Discount Condition',
|
||||||
sourceNationality: 'Source Nationality',
|
sourceNationality: 'Source Nationality',
|
||||||
importNationality: 'Import Nationality',
|
importNationality: 'Import Nationality',
|
||||||
|
|
@ -473,6 +477,7 @@ export default {
|
||||||
blacklist: 'Black list',
|
blacklist: 'Black list',
|
||||||
contactName: 'Contact Person',
|
contactName: 'Contact Person',
|
||||||
contactTel: 'Contact Number',
|
contactTel: 'Contact Number',
|
||||||
|
addressForeign: 'Use foreign address',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
customer: {
|
customer: {
|
||||||
|
|
@ -488,7 +493,7 @@ export default {
|
||||||
},
|
},
|
||||||
employer: 'Employer',
|
employer: 'Employer',
|
||||||
employerLegalEntity: 'Legal Entity',
|
employerLegalEntity: 'Legal Entity',
|
||||||
employerNaturalPerson: 'Natrual Person',
|
employerNaturalPerson: 'Natural Person',
|
||||||
employerType: 'Employer Type',
|
employerType: 'Employer Type',
|
||||||
employee: 'Employee',
|
employee: 'Employee',
|
||||||
form: {
|
form: {
|
||||||
|
|
@ -498,11 +503,12 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
prefix: {
|
prefix: {
|
||||||
mr: 'Mr.',
|
mr: 'MR.',
|
||||||
mrs: 'Mrs.',
|
mrs: 'MRS.',
|
||||||
miss: 'Miss.',
|
miss: 'MISS.',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
taxpayyerNo: 'Taxpayer Identification Number',
|
||||||
citizenId: 'Citizen ID',
|
citizenId: 'Citizen ID',
|
||||||
religion: 'Religion',
|
religion: 'Religion',
|
||||||
issueDate: 'Issue Date',
|
issueDate: 'Issue Date',
|
||||||
|
|
@ -618,7 +624,7 @@ export default {
|
||||||
placeOfBirth: 'Place of Birth',
|
placeOfBirth: 'Place of Birth',
|
||||||
countryOfbirth: 'Country of Birth',
|
countryOfbirth: 'Country of Birth',
|
||||||
issueCountry: 'Issue Country',
|
issueCountry: 'Issue Country',
|
||||||
entryCount: 'Entry Count',
|
entryCount: 'Number of Days in the Country',
|
||||||
employerSelect: {
|
employerSelect: {
|
||||||
branchName: 'Branch Name',
|
branchName: 'Branch Name',
|
||||||
customerName: 'Employer Name',
|
customerName: 'Employer Name',
|
||||||
|
|
@ -768,10 +774,13 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
quotation: {
|
quotation: {
|
||||||
|
ownOnly: 'View Own Quotation Only',
|
||||||
quotationDate: 'Quotation Date',
|
quotationDate: 'Quotation Date',
|
||||||
seller: 'Seller',
|
seller: 'Seller',
|
||||||
paymentChannels: 'Payment Channels',
|
paymentChannels: 'Payment Channels',
|
||||||
channelsThat: 'Channels That',
|
channelsThat: 'Channels That',
|
||||||
|
refNo: 'Reference Number',
|
||||||
|
bankAccount: 'Bank Account',
|
||||||
bankAccountNumber: 'Bank Account Number',
|
bankAccountNumber: 'Bank Account Number',
|
||||||
bankAccountName: 'Bank Account Name',
|
bankAccountName: 'Bank Account Name',
|
||||||
inTheNameOf: 'In The Name Of',
|
inTheNameOf: 'In The Name Of',
|
||||||
|
|
@ -923,6 +932,7 @@ export default {
|
||||||
contactName: 'Contact Person',
|
contactName: 'Contact Person',
|
||||||
contactTel: 'Contact Number',
|
contactTel: 'Contact Number',
|
||||||
bankInfo: 'Bank Information',
|
bankInfo: 'Bank Information',
|
||||||
|
attachment: 'Attachment',
|
||||||
},
|
},
|
||||||
|
|
||||||
requestList: {
|
requestList: {
|
||||||
|
|
@ -1117,7 +1127,7 @@ export default {
|
||||||
oneOrMoreBranchMissing:
|
oneOrMoreBranchMissing:
|
||||||
'One or more branch cannot be delete and is missing.',
|
'One or more branch cannot be delete and is missing.',
|
||||||
cantMakeHQAndBranchSameTime:
|
cantMakeHQAndBranchSameTime:
|
||||||
'Cannot make this as headquaters and branch at the same time.',
|
'Cannot make this as headquarters and branch at the same time.',
|
||||||
unknowHowToVerify: 'Unknown how to verify identity.',
|
unknowHowToVerify: 'Unknown how to verify identity.',
|
||||||
noPermission:
|
noPermission:
|
||||||
'You do not have permission to access or perform with this resource.',
|
'You do not have permission to access or perform with this resource.',
|
||||||
|
|
@ -1224,6 +1234,9 @@ export default {
|
||||||
taskListNotPending: 'One or more task is not pending.',
|
taskListNotPending: 'One or more task is not pending.',
|
||||||
reqNotMet: 'Not Match',
|
reqNotMet: 'Not Match',
|
||||||
systemError: 'A system error occurred.',
|
systemError: 'A system error occurred.',
|
||||||
|
taskOrderInvalid: 'Please select the product and the organization.',
|
||||||
|
|
||||||
|
flowAccountProductIdNotFound: 'Product not found in flow account',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -1508,4 +1521,11 @@ export default {
|
||||||
last90Days: 'Last 90 Days',
|
last90Days: 'Last 90 Days',
|
||||||
customDateRange: 'Custom Date Range',
|
customDateRange: 'Custom Date Range',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
businessType: {
|
||||||
|
title: 'Business Type',
|
||||||
|
caption: 'Manage Business Type',
|
||||||
|
name: 'Business Type Name',
|
||||||
|
nameEn: 'Business Type Name (English)',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ export default {
|
||||||
save: 'บันทึก',
|
save: 'บันทึก',
|
||||||
open: 'เปิด',
|
open: 'เปิด',
|
||||||
close: 'ปิด',
|
close: 'ปิด',
|
||||||
edit: 'แก้ไข',
|
edit: 'แก้ไข{text}',
|
||||||
cancel: 'ยกเลิก',
|
cancel: 'ยกเลิก',
|
||||||
back: 'ย้อนกลับ',
|
back: 'ย้อนกลับ',
|
||||||
undo: 'ย้อนกลับ',
|
undo: 'ย้อนกลับ',
|
||||||
|
|
@ -31,6 +31,7 @@ export default {
|
||||||
displayField: 'ฟิลด์แสดงผล',
|
displayField: 'ฟิลด์แสดงผล',
|
||||||
order: 'ลำดับ',
|
order: 'ลำดับ',
|
||||||
name: 'ชื่อ{msg}',
|
name: 'ชื่อ{msg}',
|
||||||
|
nameEN: 'ชื่อ (ภาษาอังกฤษ)',
|
||||||
fullName: 'ชื่อ-สกุล',
|
fullName: 'ชื่อ-สกุล',
|
||||||
detail: 'รายละเอียด{msg}',
|
detail: 'รายละเอียด{msg}',
|
||||||
remark: 'หมายเหตุ{msg}',
|
remark: 'หมายเหตุ{msg}',
|
||||||
|
|
@ -160,6 +161,7 @@ export default {
|
||||||
documentStatus: 'สถานะเอกสาร',
|
documentStatus: 'สถานะเอกสาร',
|
||||||
advanceSearch: 'ค้นหาขั้นสูง',
|
advanceSearch: 'ค้นหาขั้นสูง',
|
||||||
totalPeople: '{meg} คน',
|
totalPeople: '{meg} คน',
|
||||||
|
price: 'ราคา {price} บาท',
|
||||||
},
|
},
|
||||||
|
|
||||||
menu: {
|
menu: {
|
||||||
|
|
@ -202,12 +204,14 @@ export default {
|
||||||
title: 'จัดการ',
|
title: 'จัดการ',
|
||||||
branch: 'สาขา',
|
branch: 'สาขา',
|
||||||
personnel: 'บุคลากร',
|
personnel: 'บุคลากร',
|
||||||
|
group: 'กลุ่ม',
|
||||||
productService: 'สินค้าและบริการ',
|
productService: 'สินค้าและบริการ',
|
||||||
workflow: 'ขั้นตอนการทำงาน',
|
workflow: 'ขั้นตอนการทำงาน',
|
||||||
property: 'คุณสมบัติ',
|
property: 'คุณสมบัติ',
|
||||||
customer: 'ลูกค้า',
|
customer: 'ลูกค้า',
|
||||||
mainData: 'ข้อมูลหลัก',
|
mainData: 'ข้อมูลหลัก',
|
||||||
agencies: 'หน่วยงาน',
|
agencies: 'หน่วยงาน',
|
||||||
|
businessType: 'ประเภทกิจการ',
|
||||||
},
|
},
|
||||||
|
|
||||||
sales: {
|
sales: {
|
||||||
|
|
@ -334,7 +338,7 @@ export default {
|
||||||
letterAndNumOnly: 'โปรดใช้เฉพาะ _ ตัวอักษรภาษาอังกฤษและตัวเลขเท่านั้น',
|
letterAndNumOnly: 'โปรดใช้เฉพาะ _ ตัวอักษรภาษาอังกฤษและตัวเลขเท่านั้น',
|
||||||
numOnly: 'โปรดใช้เฉพาะตัวเลขเท่านั้น',
|
numOnly: 'โปรดใช้เฉพาะตัวเลขเท่านั้น',
|
||||||
requireLength: 'กรุณากรอกให้ครบ {msg} หลัก',
|
requireLength: 'กรุณากรอกให้ครบ {msg} หลัก',
|
||||||
branchNameField: "โปรดใช้ตัวอักษร ตัวเลข หรือ . , - ' & เท่านั้น",
|
branchNameField: "โปรดใช้ตัวอักษร ตัวเลข หรือ . , - ' ( ) & เท่านั้น",
|
||||||
branchNameENField:
|
branchNameENField:
|
||||||
"โปรดใช้ตัวอักษรภาษาอังกฤษ ตัวเลข หรือ . , - ' & เท่านั้น",
|
"โปรดใช้ตัวอักษรภาษาอังกฤษ ตัวเลข หรือ . , - ' & เท่านั้น",
|
||||||
passportFormat: 'กรุณากรอกหมายเลขพาสปอร์ตให้ถูกต้องตามรูปแบบ',
|
passportFormat: 'กรุณากรอกหมายเลขพาสปอร์ตให้ถูกต้องตามรูปแบบ',
|
||||||
|
|
@ -469,6 +473,7 @@ export default {
|
||||||
blacklist: 'แบล็คลิสต์',
|
blacklist: 'แบล็คลิสต์',
|
||||||
contactName: 'ชื่อผู้ติดต่อ',
|
contactName: 'ชื่อผู้ติดต่อ',
|
||||||
contactTel: 'เบอร์โทรศัพท์ผู้ติดต่อ',
|
contactTel: 'เบอร์โทรศัพท์ผู้ติดต่อ',
|
||||||
|
addressForeign: 'ใช้ที่อยู่ต่างประเทศ',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
customer: {
|
customer: {
|
||||||
|
|
@ -495,15 +500,16 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
prefix: {
|
prefix: {
|
||||||
mr: 'Mr.',
|
mr: 'นาย',
|
||||||
mrs: 'Mrs.',
|
mrs: 'นาง',
|
||||||
miss: 'Miss.',
|
miss: 'นางสาว',
|
||||||
},
|
},
|
||||||
|
|
||||||
citizenId: 'บัตรประจำตัวประชาชน',
|
citizenId: 'บัตรประจำตัวประชาชน',
|
||||||
religion: 'ศาสนา',
|
religion: 'ศาสนา',
|
||||||
issueDate: 'วันที่ออกหนังสือ',
|
issueDate: 'วันที่ออกหนังสือ',
|
||||||
passportExpiryDate: 'วันหiมดอายุหนังสือเดินทาง',
|
passportExpiryDate: 'วันหiมดอายุหนังสือเดินทาง',
|
||||||
|
taxpayyerNo: 'เลขที่ประจำตัวผู้เสียภาษี',
|
||||||
|
|
||||||
ownerName: 'ชื่อนายจ้าง',
|
ownerName: 'ชื่อนายจ้าง',
|
||||||
firstName: 'ชื่อ ',
|
firstName: 'ชื่อ ',
|
||||||
|
|
@ -620,7 +626,7 @@ export default {
|
||||||
placeOfBirth: 'สถานที่เกิด',
|
placeOfBirth: 'สถานที่เกิด',
|
||||||
countryOfbirth: 'ประเทศที่เกิด',
|
countryOfbirth: 'ประเทศที่เกิด',
|
||||||
issueCountry: 'ประเทศที่ออก',
|
issueCountry: 'ประเทศที่ออก',
|
||||||
entryCount: 'จำนวนที่เข้าประเทศ',
|
entryCount: 'จำนวนวันที่เข้าประเทศ',
|
||||||
employerSelect: {
|
employerSelect: {
|
||||||
branchName: 'ชื่อสาขา',
|
branchName: 'ชื่อสาขา',
|
||||||
customerName: 'ชื่อนายจ้าง',
|
customerName: 'ชื่อนายจ้าง',
|
||||||
|
|
@ -648,7 +654,7 @@ export default {
|
||||||
permitIssuedAt: 'สถานที่ออกใบอนุญาต',
|
permitIssuedAt: 'สถานที่ออกใบอนุญาต',
|
||||||
permitIssueDate: 'วันที่ออกใบอนุญาตทำงาน',
|
permitIssueDate: 'วันที่ออกใบอนุญาตทำงาน',
|
||||||
permitExpireDate: 'วันที่หมดอายุใบอนุญาตทำงาน',
|
permitExpireDate: 'วันที่หมดอายุใบอนุญาตทำงาน',
|
||||||
identityNo: 'เลขประจำตัวคนต่างด้าว (13หลัก)',
|
identityNo: 'เลขประจำตัวคนต่างด้าว (13 หลัก)',
|
||||||
},
|
},
|
||||||
formFamily: {
|
formFamily: {
|
||||||
citizenId:
|
citizenId:
|
||||||
|
|
@ -766,10 +772,13 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
quotation: {
|
quotation: {
|
||||||
|
ownOnly: 'เห็นเฉพาะใบเสนอราคาของตัวเอง',
|
||||||
quotationDate: 'วันที่ใบเสนอราคา',
|
quotationDate: 'วันที่ใบเสนอราคา',
|
||||||
seller: 'ผู้ขาย',
|
seller: 'ผู้ขาย',
|
||||||
paymentChannels: 'ช่องทางชำระเงิน',
|
paymentChannels: 'ช่องทางชำระเงิน',
|
||||||
channelsThat: 'ช่องทางที่',
|
channelsThat: 'ช่องทางที่',
|
||||||
|
refNo: 'เลขที่อ้างอิง',
|
||||||
|
bankAccount: 'บัญชีธนาคาร',
|
||||||
bankAccountNumber: 'เลขบัญชีธนาคาร',
|
bankAccountNumber: 'เลขบัญชีธนาคาร',
|
||||||
bankAccountName: 'ชื่อบัญชี',
|
bankAccountName: 'ชื่อบัญชี',
|
||||||
inTheNameOf: 'ในนาม',
|
inTheNameOf: 'ในนาม',
|
||||||
|
|
@ -794,7 +803,7 @@ export default {
|
||||||
branch: 'สาขาที่ออกใบเสนอราคา',
|
branch: 'สาขาที่ออกใบเสนอราคา',
|
||||||
branchVirtual: 'จุดรับบริการที่ออกใบเสนอราคา',
|
branchVirtual: 'จุดรับบริการที่ออกใบเสนอราคา',
|
||||||
customer: 'ลูกค้า',
|
customer: 'ลูกค้า',
|
||||||
newCustomer: 'ลูกค้าใหม่',
|
newCustomer: 'แรงงานใหม่',
|
||||||
employeeList: 'รายชื่อแรงงาน',
|
employeeList: 'รายชื่อแรงงาน',
|
||||||
employee: 'แรงงาน',
|
employee: 'แรงงาน',
|
||||||
employeeName: 'ชื่อ-นามสกุล แรงงาน',
|
employeeName: 'ชื่อ-นามสกุล แรงงาน',
|
||||||
|
|
@ -920,6 +929,7 @@ export default {
|
||||||
contactName: 'ชื่อผู้ติดต่อ',
|
contactName: 'ชื่อผู้ติดต่อ',
|
||||||
contactTel: 'เบอร์โทรผู้ติดต่อ',
|
contactTel: 'เบอร์โทรผู้ติดต่อ',
|
||||||
bankInfo: 'ข้อมูลธนาคาร',
|
bankInfo: 'ข้อมูลธนาคาร',
|
||||||
|
attachment: 'เอกสารเพิ่มเติม',
|
||||||
},
|
},
|
||||||
|
|
||||||
requestList: {
|
requestList: {
|
||||||
|
|
@ -1210,6 +1220,8 @@ export default {
|
||||||
'มีงานหนึ่งงานหรือมากกว่าที่ไม่อยู่ในสถานะรอดำเนินการ',
|
'มีงานหนึ่งงานหรือมากกว่าที่ไม่อยู่ในสถานะรอดำเนินการ',
|
||||||
reqNotMet: 'ไม่ตรงกัน',
|
reqNotMet: 'ไม่ตรงกัน',
|
||||||
systemError: 'ระบบเกิดข้อผิดพลาด',
|
systemError: 'ระบบเกิดข้อผิดพลาด',
|
||||||
|
taskOrderInvalid: 'โปรดเลือก สินค้าเเละสาขา',
|
||||||
|
flowAccountProductIdNotFound: 'ไม่พบสินค้าใน flow account',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -1496,4 +1508,11 @@ export default {
|
||||||
last90Days: '90 วันที่ผ่านมา',
|
last90Days: '90 วันที่ผ่านมา',
|
||||||
customDateRange: 'กำหนดช่วงวันที่เอง',
|
customDateRange: 'กำหนดช่วงวันที่เอง',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
businessType: {
|
||||||
|
title: 'ประเภทกิจการ',
|
||||||
|
caption: 'จัดการประเภทกิจการ',
|
||||||
|
name: 'ชื่อประเภทกิจการ',
|
||||||
|
nameEn: 'ชื่อประเภทกิจการ (ภาษาอังกฤษ)',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import useMyBranch from 'stores/my-branch';
|
||||||
import { getUserId, getRole } from 'src/services/keycloak';
|
import { getUserId, getRole } from 'src/services/keycloak';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { isRoleInclude } from 'src/stores/utils';
|
import { canAccess } from 'src/stores/utils';
|
||||||
|
|
||||||
type Menu = {
|
type Menu = {
|
||||||
label: string;
|
label: string;
|
||||||
|
|
@ -71,82 +71,50 @@ function initMenu() {
|
||||||
{
|
{
|
||||||
label: 'branch',
|
label: 'branch',
|
||||||
route: '/branch-management',
|
route: '/branch-management',
|
||||||
hidden: !isRoleInclude([
|
hidden: !canAccess('branch'),
|
||||||
'system',
|
|
||||||
'head_of_admin',
|
|
||||||
'admin',
|
|
||||||
'branch_manager',
|
|
||||||
'head_of_accountant',
|
|
||||||
]),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'personnel',
|
label: 'personnel',
|
||||||
route: '/personnel-management',
|
route: '/personnel-management',
|
||||||
hidden: !isRoleInclude([
|
hidden: !canAccess('personnel'),
|
||||||
'owner',
|
},
|
||||||
'system',
|
{
|
||||||
'head_of_admin',
|
label: 'group',
|
||||||
'admin',
|
route: '/group-management',
|
||||||
'branch_manager',
|
hidden: !canAccess('personnel'),
|
||||||
]),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'workflow',
|
label: 'workflow',
|
||||||
route: '/workflow',
|
route: '/workflow',
|
||||||
hidden: !isRoleInclude(['system', 'head_of_admin', 'admin']),
|
hidden: !canAccess('workflow'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'property',
|
label: 'property',
|
||||||
route: '/property',
|
route: '/property',
|
||||||
hidden: !isRoleInclude(['system', 'head_of_admin', 'admin']),
|
hidden: !canAccess('workflow'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'businessType',
|
||||||
|
route: '/business-type',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'productService',
|
label: 'productService',
|
||||||
route: '/product-service',
|
route: '/product-service',
|
||||||
hidden: !isRoleInclude([
|
|
||||||
'system',
|
|
||||||
'head_of_admin',
|
|
||||||
'admin',
|
|
||||||
'branch_manager',
|
|
||||||
'head_of_accountant',
|
|
||||||
'head_of_sale',
|
|
||||||
'sale',
|
|
||||||
]),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'customer',
|
label: 'customer',
|
||||||
route: '/customer-management',
|
route: '/customer-management',
|
||||||
hidden: !isRoleInclude([
|
hidden: !canAccess('customer'),
|
||||||
'system',
|
|
||||||
'head_of_admin',
|
|
||||||
'admin',
|
|
||||||
'branch_manager',
|
|
||||||
'head_of_accountant',
|
|
||||||
'accountant',
|
|
||||||
'head_of_sale',
|
|
||||||
'sale',
|
|
||||||
]),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'agencies',
|
label: 'agencies',
|
||||||
route: '/agencies-management',
|
route: '/agencies-management',
|
||||||
hidden: !isRoleInclude(['system', 'head_of_admin', 'admin']),
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'menu.sales',
|
label: 'menu.sales',
|
||||||
icon: 'mdi-store-settings-outline',
|
icon: 'mdi-store-settings-outline',
|
||||||
hidden: !isRoleInclude([
|
|
||||||
'system',
|
|
||||||
'head_of_admin',
|
|
||||||
'admin',
|
|
||||||
'branch_manager',
|
|
||||||
'head_of_accountant',
|
|
||||||
'accountant',
|
|
||||||
'head_of_sale',
|
|
||||||
'sale',
|
|
||||||
]),
|
|
||||||
children: [
|
children: [
|
||||||
{ label: 'quotation', route: '/quotation' },
|
{ label: 'quotation', route: '/quotation' },
|
||||||
{ label: 'invoice', route: '/invoice' },
|
{ label: 'invoice', route: '/invoice' },
|
||||||
|
|
@ -169,16 +137,6 @@ function initMenu() {
|
||||||
label: 'menu.account',
|
label: 'menu.account',
|
||||||
icon: 'mdi-bank-outline',
|
icon: 'mdi-bank-outline',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
hidden: !isRoleInclude([
|
|
||||||
'system',
|
|
||||||
'head_of_admin',
|
|
||||||
'admin',
|
|
||||||
'branch_manager',
|
|
||||||
'head_of_accountant',
|
|
||||||
'accountant',
|
|
||||||
'head_of_sale',
|
|
||||||
'sale',
|
|
||||||
]),
|
|
||||||
children: [
|
children: [
|
||||||
{ label: 'receipt', route: '/receipt' },
|
{ label: 'receipt', route: '/receipt' },
|
||||||
{ label: 'creditNote', route: '/credit-note' },
|
{ label: 'creditNote', route: '/credit-note' },
|
||||||
|
|
@ -200,10 +158,13 @@ function initMenu() {
|
||||||
{
|
{
|
||||||
label: 'menu.overall',
|
label: 'menu.overall',
|
||||||
icon: 'mdi-monitor-dashboard',
|
icon: 'mdi-monitor-dashboard',
|
||||||
hidden: !isRoleInclude(['system', 'head_of_admin', 'admin', 'executive']),
|
|
||||||
children: [
|
children: [
|
||||||
{ label: 'report', route: '/report' },
|
{ label: 'report', route: '/report' },
|
||||||
{ label: 'dashboard', route: '/dash-board' },
|
{
|
||||||
|
label: 'dashboard',
|
||||||
|
route: '/dash-board',
|
||||||
|
hidden: !canAccess('dashBoard'),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
import { ref, onMounted, computed, reactive } from 'vue';
|
import { ref, onMounted, computed, reactive } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
import { getUserId, getUsername, logout, getRole } from 'src/services/keycloak';
|
import { getUserId, getUsername, getName, logout, getRole } from 'src/services/keycloak';
|
||||||
import { Icon } from '@iconify/vue';
|
import { Icon } from '@iconify/vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
@ -39,7 +39,7 @@ const configStore = useConfigStore();
|
||||||
const { data: notificationData } = storeToRefs(notificationStore);
|
const { data: notificationData } = storeToRefs(notificationStore);
|
||||||
|
|
||||||
const { visible } = storeToRefs(loaderStore);
|
const { visible } = storeToRefs(loaderStore);
|
||||||
const { t } = useI18n({ useScope: 'global' });
|
const { t, locale } = useI18n({ useScope: 'global' });
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
const canvasModal = ref(false);
|
const canvasModal = ref(false);
|
||||||
|
|
@ -52,8 +52,14 @@ const unread = computed<number>(
|
||||||
);
|
);
|
||||||
const userImage = ref<string>();
|
const userImage = ref<string>();
|
||||||
const userGender = ref('');
|
const userGender = ref('');
|
||||||
|
const userName = ref({ th: '', en: '' });
|
||||||
const canvasRef = ref();
|
const canvasRef = ref();
|
||||||
|
|
||||||
|
const displayName = computed(() => {
|
||||||
|
if (!userName.value.th && !userName.value.en) return getName() || 'Guest';
|
||||||
|
return locale.value === 'eng' ? userName.value.en : userName.value.th;
|
||||||
|
});
|
||||||
|
|
||||||
const language: {
|
const language: {
|
||||||
value: Lang;
|
value: Lang;
|
||||||
label: string;
|
label: string;
|
||||||
|
|
@ -161,9 +167,14 @@ onMounted(async () => {
|
||||||
if (user === 'admin') return;
|
if (user === 'admin') return;
|
||||||
if (uid) {
|
if (uid) {
|
||||||
const res = await userStore.fetchById(uid);
|
const res = await userStore.fetchById(uid);
|
||||||
if (res && res.gender) {
|
if (res) {
|
||||||
userGender.value = res.gender;
|
if (res.gender) {
|
||||||
userImage.value = `${baseUrl}/user/${uid}/profile-image/${res.selectedImage}`;
|
userGender.value = res.gender;
|
||||||
|
userImage.value = `${baseUrl}/user/${uid}/profile-image/${res.selectedImage}`;
|
||||||
|
}
|
||||||
|
// เก็บชื่อทั้งสองภาษา
|
||||||
|
userName.value.th = `${res.firstName || ''} ${res.lastName || ''}`.trim();
|
||||||
|
userName.value.en = `${res.firstNameEN || ''} ${res.lastNameEN || ''}`.trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -484,6 +495,7 @@ onMounted(async () => {
|
||||||
<!-- User -->
|
<!-- User -->
|
||||||
<ProfileMenu
|
<ProfileMenu
|
||||||
id="btn-profile-menu"
|
id="btn-profile-menu"
|
||||||
|
:user-name="displayName"
|
||||||
@logout="doLogout"
|
@logout="doLogout"
|
||||||
@edit-personal-info="console.log('edit')"
|
@edit-personal-info="console.log('edit')"
|
||||||
@signature="
|
@signature="
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ const filterRole = ref<string[]>();
|
||||||
defineProps<{
|
defineProps<{
|
||||||
userImage?: string;
|
userImage?: string;
|
||||||
gender?: string;
|
gender?: string;
|
||||||
|
userName?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const inputFile = document.createElement('input');
|
const inputFile = document.createElement('input');
|
||||||
|
|
@ -147,9 +148,9 @@ onMounted(async () => {
|
||||||
class="text-weight-bold ellipsis"
|
class="text-weight-bold ellipsis"
|
||||||
style="max-width: 9vw"
|
style="max-width: 9vw"
|
||||||
>
|
>
|
||||||
{{ getName() }}
|
{{ userName || getName() }}
|
||||||
<q-tooltip>
|
<q-tooltip>
|
||||||
{{ getName() }}
|
{{ userName || getName() }}
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
|
|
@ -234,12 +235,12 @@ onMounted(async () => {
|
||||||
style="margin-top: 58px"
|
style="margin-top: 58px"
|
||||||
>
|
>
|
||||||
<span v-if="isLoggedIn()">
|
<span v-if="isLoggedIn()">
|
||||||
{{ getName() }}
|
{{ userName || getName() }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else>{{ 'Guest' }}</span>
|
<span v-else>{{ 'Guest' }}</span>
|
||||||
<q-tooltip>
|
<q-tooltip>
|
||||||
<span v-if="isLoggedIn()">
|
<span v-if="isLoggedIn()">
|
||||||
{{ getName() }}
|
{{ userName || getName() }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else>{{ 'Guest' }}</span>
|
<span v-else>{{ 'Guest' }}</span>
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import type { QTableProps, QTableSlots } from 'quasar';
|
||||||
import { resetScrollBar } from 'src/stores/utils';
|
import { resetScrollBar } from 'src/stores/utils';
|
||||||
import useBranchStore from 'stores/branch';
|
import useBranchStore from 'stores/branch';
|
||||||
import useFlowStore from 'stores/flow';
|
import useFlowStore from 'stores/flow';
|
||||||
import { isRoleInclude } from 'stores/utils';
|
import { isRoleInclude, canAccess } from 'stores/utils';
|
||||||
import {
|
import {
|
||||||
BranchWithChildren,
|
BranchWithChildren,
|
||||||
BranchCreate,
|
BranchCreate,
|
||||||
|
|
@ -791,6 +791,8 @@ async function onSubmit(submitSelectedItem?: boolean) {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!res) return;
|
if (!res) return;
|
||||||
|
|
||||||
|
formType.value = 'view';
|
||||||
formData.value.codeHeadOffice = formData.value.code = res.code;
|
formData.value.codeHeadOffice = formData.value.code = res.code;
|
||||||
imageUrl.value = `${baseUrl}/branch/${res.id}/image/${res.selectedImage}`;
|
imageUrl.value = `${baseUrl}/branch/${res.id}/image/${res.selectedImage}`;
|
||||||
|
|
||||||
|
|
@ -865,7 +867,9 @@ async function onSubmit(submitSelectedItem?: boolean) {
|
||||||
actionText: t('dialog.action.ok'),
|
actionText: t('dialog.action.ok'),
|
||||||
persistent: true,
|
persistent: true,
|
||||||
title: t('form.warning.title'),
|
title: t('form.warning.title'),
|
||||||
cancel: () => {},
|
cancel: () => {
|
||||||
|
formType.value = 'create';
|
||||||
|
},
|
||||||
action: async () => {
|
action: async () => {
|
||||||
await createBranch();
|
await createBranch();
|
||||||
},
|
},
|
||||||
|
|
@ -1046,7 +1050,7 @@ watch(currentHq, () => {
|
||||||
{{ $t('branch.allBranch') }}
|
{{ $t('branch.allBranch') }}
|
||||||
</div>
|
</div>
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="isRoleInclude(['head_of_admin', 'admin', 'system'])"
|
v-if="isRoleInclude(['system'])"
|
||||||
round
|
round
|
||||||
flat
|
flat
|
||||||
size="md"
|
size="md"
|
||||||
|
|
@ -1070,6 +1074,7 @@ watch(currentHq, () => {
|
||||||
<div class="col full-width scroll">
|
<div class="col full-width scroll">
|
||||||
<div class="q-pa-md">
|
<div class="q-pa-md">
|
||||||
<TreeComponent
|
<TreeComponent
|
||||||
|
:hide-create="!canAccess('branch', 'create')"
|
||||||
v-model:nodes="treeData"
|
v-model:nodes="treeData"
|
||||||
v-model:expanded-tree="expandedTree"
|
v-model:expanded-tree="expandedTree"
|
||||||
node-key="id"
|
node-key="id"
|
||||||
|
|
@ -1557,8 +1562,18 @@ watch(currentHq, () => {
|
||||||
</q-td>
|
</q-td>
|
||||||
<q-td>
|
<q-td>
|
||||||
<KebabAction
|
<KebabAction
|
||||||
|
v-if="
|
||||||
|
!currentHq.id
|
||||||
|
? canAccess('branch', 'create')
|
||||||
|
: true
|
||||||
|
"
|
||||||
:status="props.row.status"
|
:status="props.row.status"
|
||||||
:idName="props.row.name"
|
:idName="props.row.name"
|
||||||
|
:hide-delete="
|
||||||
|
!currentHq.id
|
||||||
|
? !isRoleInclude(['system'])
|
||||||
|
: !canAccess('branch', 'create')
|
||||||
|
"
|
||||||
@view="
|
@view="
|
||||||
if (props.row.isHeadOffice) {
|
if (props.row.isHeadOffice) {
|
||||||
triggerEdit(
|
triggerEdit(
|
||||||
|
|
@ -1698,8 +1713,18 @@ watch(currentHq, () => {
|
||||||
>
|
>
|
||||||
<template v-slot:action>
|
<template v-slot:action>
|
||||||
<KebabAction
|
<KebabAction
|
||||||
|
v-if="
|
||||||
|
!currentHq.id
|
||||||
|
? canAccess('branch', 'create')
|
||||||
|
: true
|
||||||
|
"
|
||||||
:status="props.row.status"
|
:status="props.row.status"
|
||||||
:idName="props.row.name"
|
:idName="props.row.name"
|
||||||
|
:hide-delete="
|
||||||
|
!currentHq.id
|
||||||
|
? !isRoleInclude(['system'])
|
||||||
|
: !canAccess('branch', 'create')
|
||||||
|
"
|
||||||
@view="
|
@view="
|
||||||
if (props.row.isHeadOffice) {
|
if (props.row.isHeadOffice) {
|
||||||
triggerEdit(
|
triggerEdit(
|
||||||
|
|
@ -2247,13 +2272,22 @@ watch(currentHq, () => {
|
||||||
@click="drawerEdit()"
|
@click="drawerEdit()"
|
||||||
type="button"
|
type="button"
|
||||||
/>
|
/>
|
||||||
<DeleteButton
|
|
||||||
v-if="formType !== 'edit'"
|
<template
|
||||||
id="btn-info-basic-delete"
|
v-if="
|
||||||
icon-only
|
formType !== 'edit' && formTypeBranch === 'headOffice'
|
||||||
@click="triggerDelete(currentEdit.id)"
|
? isRoleInclude(['system'])
|
||||||
type="button"
|
: canAccess('branch', 'create')
|
||||||
/>
|
"
|
||||||
|
>
|
||||||
|
<DeleteButton
|
||||||
|
v-if="formType !== 'edit'"
|
||||||
|
id="btn-info-basic-delete"
|
||||||
|
icon-only
|
||||||
|
@click="triggerDelete(currentEdit.id)"
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
67
src/pages/02_group-management/MainPage.vue
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, ref, watch } from 'vue';
|
||||||
|
import { getInstance } from 'src/services/keycloak';
|
||||||
|
import { useNavigator } from 'src/stores/navigator';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
import { initLang } from 'src/utils/ui';
|
||||||
|
|
||||||
|
const $q = useQuasar();
|
||||||
|
const { locale } = useI18n();
|
||||||
|
const navigatorStore = useNavigator();
|
||||||
|
const EDM_SERVICE = import.meta.env.VITE_EDM_MICRO_FRONTEND_URL;
|
||||||
|
const kc = getInstance();
|
||||||
|
const at = ref(kc.token);
|
||||||
|
const rt = ref(kc.refreshToken);
|
||||||
|
const iframe = ref<InstanceType<typeof HTMLIFrameElement>>();
|
||||||
|
|
||||||
|
function sendMessage() {
|
||||||
|
iframe?.value?.contentWindow?.postMessage(
|
||||||
|
{
|
||||||
|
i18n: locale.value,
|
||||||
|
darkMode: $q.dark.isActive,
|
||||||
|
},
|
||||||
|
'*',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initLang();
|
||||||
|
currentLocale.value = locale.value;
|
||||||
|
navigatorStore.current.title = 'menu.dms';
|
||||||
|
navigatorStore.current.path = [
|
||||||
|
{
|
||||||
|
text: '',
|
||||||
|
i18n: true,
|
||||||
|
handler: () => {},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
sendMessage();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => kc.token,
|
||||||
|
() => {
|
||||||
|
at.value = kc.token;
|
||||||
|
rt.value = kc.refreshToken;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
watch([locale, $q.dark], () => {
|
||||||
|
sendMessage();
|
||||||
|
});
|
||||||
|
|
||||||
|
const currentLocale = ref(locale.value);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<iframe
|
||||||
|
ref="iframe"
|
||||||
|
:src="`${EDM_SERVICE}/user?at=${at}&rt=${rt}&lang=${currentLocale}`"
|
||||||
|
frameborder="0"
|
||||||
|
class="full-width full-height rounded"
|
||||||
|
allowtransparency="true"
|
||||||
|
></iframe>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
|
|
@ -157,6 +157,14 @@ const defaultFormData = {
|
||||||
contactTel: '',
|
contactTel: '',
|
||||||
remark: '',
|
remark: '',
|
||||||
agencyStatus: '',
|
agencyStatus: '',
|
||||||
|
addressForeign: false,
|
||||||
|
provinceText: null,
|
||||||
|
districtText: null,
|
||||||
|
subDistrictText: null,
|
||||||
|
provinceTextEN: null,
|
||||||
|
districtTextEN: null,
|
||||||
|
subDistrictTextEN: null,
|
||||||
|
zipCodeText: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const formData = ref<UserCreate>({
|
const formData = ref<UserCreate>({
|
||||||
|
|
@ -209,6 +217,14 @@ const formData = ref<UserCreate>({
|
||||||
contactTel: '',
|
contactTel: '',
|
||||||
remark: '',
|
remark: '',
|
||||||
agencyStatus: '',
|
agencyStatus: '',
|
||||||
|
addressForeign: false,
|
||||||
|
provinceText: null,
|
||||||
|
districtText: null,
|
||||||
|
subDistrictText: null,
|
||||||
|
provinceTextEN: null,
|
||||||
|
districtTextEN: null,
|
||||||
|
subDistrictTextEN: null,
|
||||||
|
zipCodeText: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const fieldSelectedOption = ref<{ label: string; value: string }[]>([
|
const fieldSelectedOption = ref<{ label: string; value: string }[]>([
|
||||||
|
|
@ -431,6 +447,28 @@ async function onSubmit(excludeDialog?: boolean) {
|
||||||
...formData.value,
|
...formData.value,
|
||||||
checkpointEN: formData.value.checkpoint,
|
checkpointEN: formData.value.checkpoint,
|
||||||
status: !statusToggle.value ? 'INACTIVE' : 'ACTIVE',
|
status: !statusToggle.value ? 'INACTIVE' : 'ACTIVE',
|
||||||
|
provinceId: formData.value.addressForeign
|
||||||
|
? null
|
||||||
|
: formData.value.provinceId,
|
||||||
|
districtId: formData.value.addressForeign
|
||||||
|
? null
|
||||||
|
: formData.value.districtId,
|
||||||
|
subDistrictId: formData.value.addressForeign
|
||||||
|
? null
|
||||||
|
: formData.value.subDistrictId,
|
||||||
|
|
||||||
|
provinceText: formData.value.addressForeign
|
||||||
|
? formData.value.provinceId
|
||||||
|
: null,
|
||||||
|
districtText: formData.value.addressForeign
|
||||||
|
? formData.value.districtId
|
||||||
|
: null,
|
||||||
|
subDistrictText: formData.value.addressForeign
|
||||||
|
? formData.value.subDistrictId
|
||||||
|
: null,
|
||||||
|
zipCodeText: formData.value.addressForeign
|
||||||
|
? formData.value.zipCode
|
||||||
|
: null,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
await userStore.editById(currentUser.value.id, formDataEdit);
|
await userStore.editById(currentUser.value.id, formDataEdit);
|
||||||
|
|
@ -462,7 +500,31 @@ async function onSubmit(excludeDialog?: boolean) {
|
||||||
: '';
|
: '';
|
||||||
formData.value.checkpointEN = formData.value.checkpoint;
|
formData.value.checkpointEN = formData.value.checkpoint;
|
||||||
const result = await userStore.create(
|
const result = await userStore.create(
|
||||||
formData.value,
|
{
|
||||||
|
...formData.value,
|
||||||
|
provinceId: formData.value.addressForeign
|
||||||
|
? null
|
||||||
|
: formData.value.provinceId,
|
||||||
|
districtId: formData.value.addressForeign
|
||||||
|
? null
|
||||||
|
: formData.value.districtId,
|
||||||
|
subDistrictId: formData.value.addressForeign
|
||||||
|
? null
|
||||||
|
: formData.value.subDistrictId,
|
||||||
|
|
||||||
|
provinceText: formData.value.addressForeign
|
||||||
|
? formData.value.provinceId
|
||||||
|
: null,
|
||||||
|
districtText: formData.value.addressForeign
|
||||||
|
? formData.value.districtId
|
||||||
|
: null,
|
||||||
|
subDistrictText: formData.value.addressForeign
|
||||||
|
? formData.value.subDistrictId
|
||||||
|
: null,
|
||||||
|
zipCodeText: formData.value.addressForeign
|
||||||
|
? formData.value.zipCode
|
||||||
|
: null,
|
||||||
|
},
|
||||||
onCreateImageList.value,
|
onCreateImageList.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -560,12 +622,20 @@ async function assignFormData(idEdit: string) {
|
||||||
currentUser.value = foundUser;
|
currentUser.value = foundUser;
|
||||||
formData.value = {
|
formData.value = {
|
||||||
branchId: foundUser.branch[0]?.id,
|
branchId: foundUser.branch[0]?.id,
|
||||||
provinceId: foundUser.provinceId,
|
provinceId: foundUser.addressForeign
|
||||||
districtId: foundUser.districtId,
|
? foundUser.provinceText
|
||||||
subDistrictId: foundUser.subDistrictId,
|
: foundUser.provinceId,
|
||||||
|
districtId: foundUser.addressForeign
|
||||||
|
? foundUser.districtText
|
||||||
|
: foundUser.districtId,
|
||||||
|
subDistrictId: foundUser.addressForeign
|
||||||
|
? foundUser.subDistrictText
|
||||||
|
: foundUser.subDistrictId,
|
||||||
telephoneNo: foundUser.telephoneNo,
|
telephoneNo: foundUser.telephoneNo,
|
||||||
email: foundUser.email,
|
email: foundUser.email,
|
||||||
zipCode: foundUser.zipCode,
|
zipCode: foundUser.addressForeign
|
||||||
|
? foundUser.zipCodeText
|
||||||
|
: foundUser.zipCode,
|
||||||
gender: foundUser.gender,
|
gender: foundUser.gender,
|
||||||
addressEN: foundUser.addressEN,
|
addressEN: foundUser.addressEN,
|
||||||
address: foundUser.address,
|
address: foundUser.address,
|
||||||
|
|
@ -619,6 +689,10 @@ async function assignFormData(idEdit: string) {
|
||||||
(foundUser.citizenExpire && new Date(foundUser.citizenExpire)) || null,
|
(foundUser.citizenExpire && new Date(foundUser.citizenExpire)) || null,
|
||||||
remark: foundUser.remark || '',
|
remark: foundUser.remark || '',
|
||||||
agencyStatus: foundUser.agencyStatus || '',
|
agencyStatus: foundUser.agencyStatus || '',
|
||||||
|
addressForeign: foundUser.addressForeign || false,
|
||||||
|
provinceTextEN: foundUser.provinceTextEN,
|
||||||
|
districtTextEN: foundUser.districtTextEN,
|
||||||
|
subDistrictTextEN: foundUser.subDistrictTextEN,
|
||||||
};
|
};
|
||||||
|
|
||||||
formData.value.status === 'ACTIVE' || 'CREATED'
|
formData.value.status === 'ACTIVE' || 'CREATED'
|
||||||
|
|
@ -745,7 +819,17 @@ watch(
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => formData.value.userType,
|
() => formData.value.userType,
|
||||||
async () => {
|
async (type) => {
|
||||||
|
if (type !== 'AGENCY') {
|
||||||
|
formData.value.addressForeign = false;
|
||||||
|
formData.value.provinceId = null;
|
||||||
|
formData.value.districtId = null;
|
||||||
|
formData.value.subDistrictId = null;
|
||||||
|
formData.value.provinceTextEN = null;
|
||||||
|
formData.value.districtTextEN = null;
|
||||||
|
formData.value.subDistrictTextEN = null;
|
||||||
|
formData.value.zipCodeText = null;
|
||||||
|
}
|
||||||
if (!infoDrawerEdit.value) return;
|
if (!infoDrawerEdit.value) return;
|
||||||
formData.value.registrationNo = null;
|
formData.value.registrationNo = null;
|
||||||
formData.value.startDate = null;
|
formData.value.startDate = null;
|
||||||
|
|
@ -1278,7 +1362,7 @@ watch(
|
||||||
{{
|
{{
|
||||||
locale === 'eng'
|
locale === 'eng'
|
||||||
? `${props.row.firstNameEN} ${props.row.lastNameEN}`.trim()
|
? `${props.row.firstNameEN} ${props.row.lastNameEN}`.trim()
|
||||||
: `${props.row.firstName} ${props.row.lastName}`.trim()
|
: `${props.row.firstName || props.row.firstNameEN} ${props.row.lastName || props.row.lastNameEN}`.trim()
|
||||||
}}
|
}}
|
||||||
<q-tooltip
|
<q-tooltip
|
||||||
anchor="bottom left"
|
anchor="bottom left"
|
||||||
|
|
@ -1288,7 +1372,7 @@ watch(
|
||||||
{{
|
{{
|
||||||
locale === 'eng'
|
locale === 'eng'
|
||||||
? `${props.row.firstNameEN} ${props.row.lastNameEN}`.trim()
|
? `${props.row.firstNameEN} ${props.row.lastNameEN}`.trim()
|
||||||
: `${props.row.firstName} ${props.row.lastName}`.trim()
|
: `${props.row.firstName || props.row.firstNameEN} ${props.row.lastName || props.row.lastNameEN}`.trim()
|
||||||
}}
|
}}
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
|
|
||||||
|
|
@ -1554,9 +1638,12 @@ watch(
|
||||||
hide-action
|
hide-action
|
||||||
:is-edit="infoDrawerEdit"
|
:is-edit="infoDrawerEdit"
|
||||||
:title="
|
:title="
|
||||||
locale === 'eng'
|
(currentUser.namePrefix
|
||||||
|
? $t('customer.form.prefix.' + currentUser.namePrefix) + ' '
|
||||||
|
: '') +
|
||||||
|
(locale === 'eng'
|
||||||
? `${currentUser.firstNameEN} ${currentUser.lastNameEN}`
|
? `${currentUser.firstNameEN} ${currentUser.lastNameEN}`
|
||||||
: `${currentUser.firstName} ${currentUser.lastName}`
|
: `${currentUser.firstName || currentUser.firstNameEN} ${currentUser.lastName || currentUser.lastNameEN}`)
|
||||||
"
|
"
|
||||||
v-model:drawerOpen="infoDrawer"
|
v-model:drawerOpen="infoDrawer"
|
||||||
:submit="() => onSubmit()"
|
:submit="() => onSubmit()"
|
||||||
|
|
@ -1592,8 +1679,8 @@ watch(
|
||||||
setPrefixName(
|
setPrefixName(
|
||||||
{
|
{
|
||||||
namePrefix: formData.namePrefix,
|
namePrefix: formData.namePrefix,
|
||||||
firstName: formData.firstName,
|
firstName: formData.firstName || formData.firstNameEN,
|
||||||
lastName: formData.lastName,
|
lastName: formData.lastName || formData.lastNameEN,
|
||||||
firstNameEN: formData.firstNameEN,
|
firstNameEN: formData.firstNameEN,
|
||||||
lastNameEN: formData.lastNameEN,
|
lastNameEN: formData.lastNameEN,
|
||||||
},
|
},
|
||||||
|
|
@ -1810,10 +1897,15 @@ watch(
|
||||||
v-model:district-id="formData.districtId"
|
v-model:district-id="formData.districtId"
|
||||||
v-model:sub-district-id="formData.subDistrictId"
|
v-model:sub-district-id="formData.subDistrictId"
|
||||||
v-model:zip-code="formData.zipCode"
|
v-model:zip-code="formData.zipCode"
|
||||||
|
v-model:address-foreign="formData.addressForeign"
|
||||||
|
v-model:province-text-en="formData.provinceTextEN"
|
||||||
|
v-model:district-text-en="formData.districtTextEN"
|
||||||
|
v-model:sub-district-text-en="formData.subDistrictTextEN"
|
||||||
:readonly="!infoDrawerEdit"
|
:readonly="!infoDrawerEdit"
|
||||||
prefix-id="drawer-info-personnel"
|
prefix-id="drawer-info-personnel"
|
||||||
:title="'personnel.form.addressInformation'"
|
:title="'personnel.form.addressInformation'"
|
||||||
dense
|
dense
|
||||||
|
:use-foreign-address="formData.userType === 'AGENCY'"
|
||||||
class="q-mb-xl"
|
class="q-mb-xl"
|
||||||
/>
|
/>
|
||||||
<FormByType
|
<FormByType
|
||||||
|
|
@ -2039,8 +2131,13 @@ watch(
|
||||||
v-model:district-id="formData.districtId"
|
v-model:district-id="formData.districtId"
|
||||||
v-model:sub-district-id="formData.subDistrictId"
|
v-model:sub-district-id="formData.subDistrictId"
|
||||||
v-model:zip-code="formData.zipCode"
|
v-model:zip-code="formData.zipCode"
|
||||||
|
v-model:address-foreign="formData.addressForeign"
|
||||||
|
v-model:province-text-en="formData.provinceTextEN"
|
||||||
|
v-model:district-text-en="formData.districtTextEN"
|
||||||
|
v-model:sub-district-text-en="formData.subDistrictTextEN"
|
||||||
prefix-id="drawer-info-personnel"
|
prefix-id="drawer-info-personnel"
|
||||||
dense
|
dense
|
||||||
|
:use-foreign-address="formData.userType === 'AGENCY'"
|
||||||
class="q-mb-xl"
|
class="q-mb-xl"
|
||||||
/>
|
/>
|
||||||
<FormByType
|
<FormByType
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { baseUrl } from 'src/stores/utils';
|
||||||
import useCustomerStore from 'stores/customer';
|
import useCustomerStore from 'stores/customer';
|
||||||
import useFlowStore from 'stores/flow';
|
import useFlowStore from 'stores/flow';
|
||||||
import useOptionStore from 'stores/options';
|
import useOptionStore from 'stores/options';
|
||||||
import { dialog } from 'stores/utils';
|
import { dialog, canAccess } from 'stores/utils';
|
||||||
|
|
||||||
import { Status } from 'stores/types';
|
import { Status } from 'stores/types';
|
||||||
import { Employee } from 'stores/employee/types';
|
import { Employee } from 'stores/employee/types';
|
||||||
|
|
@ -18,6 +18,8 @@ import { CustomerBranch, CustomerType } from 'stores/customer/types';
|
||||||
import { columnsEmployee } from './constant';
|
import { columnsEmployee } from './constant';
|
||||||
import { useCustomerBranchForm, useEmployeeForm } from './form';
|
import { useCustomerBranchForm, useEmployeeForm } from './form';
|
||||||
|
|
||||||
|
import DialogEmployee from 'src/components/03_customer-management/DialogEmployee.vue';
|
||||||
|
import DrawerEmployee from 'src/components/03_customer-management/DrawerEmployee.vue';
|
||||||
import EmployerFormAuthorized from './components/employer/EmployerFormAuthorized.vue';
|
import EmployerFormAuthorized from './components/employer/EmployerFormAuthorized.vue';
|
||||||
import FloatingActionButton from 'components/FloatingActionButton.vue';
|
import FloatingActionButton from 'components/FloatingActionButton.vue';
|
||||||
import SideMenu from 'components/SideMenu.vue';
|
import SideMenu from 'components/SideMenu.vue';
|
||||||
|
|
@ -89,6 +91,11 @@ const prop = withDefaults(
|
||||||
currentCitizenId?: string;
|
currentCitizenId?: string;
|
||||||
gender: string;
|
gender: string;
|
||||||
selectedImage: string;
|
selectedImage: string;
|
||||||
|
fetchImageList: (
|
||||||
|
id: string,
|
||||||
|
selectedName: string,
|
||||||
|
type: 'customer' | 'employee',
|
||||||
|
) => Promise<void>;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
color: 'green',
|
color: 'green',
|
||||||
|
|
@ -96,7 +103,6 @@ const prop = withDefaults(
|
||||||
);
|
);
|
||||||
const currentBranchEmployee = ref<string>('');
|
const currentBranchEmployee = ref<string>('');
|
||||||
const listEmployee = ref<Employee[]>([]);
|
const listEmployee = ref<Employee[]>([]);
|
||||||
|
|
||||||
const customerId = defineModel<string>('customerId', { required: true });
|
const customerId = defineModel<string>('customerId', { required: true });
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
|
|
@ -106,16 +112,6 @@ defineEmits<{
|
||||||
(e: 'dialog'): void;
|
(e: 'dialog'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
customerBranchFormState.value.currentCustomerId = route.params
|
|
||||||
.customerId as string;
|
|
||||||
await fetchList();
|
|
||||||
|
|
||||||
branch.value?.forEach((v) => {
|
|
||||||
currentBtnOpen.value.push(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
name: 'branchName',
|
name: 'branchName',
|
||||||
|
|
@ -257,10 +253,6 @@ async function fetchEmployee(opts: { branchId: string; pageSize?: number }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
await fetchList();
|
|
||||||
});
|
|
||||||
|
|
||||||
watch([customerId, inputSearch, currentStatus, pageSizeBranch], async () => {
|
watch([customerId, inputSearch, currentStatus, pageSizeBranch], async () => {
|
||||||
await fetchList();
|
await fetchList();
|
||||||
});
|
});
|
||||||
|
|
@ -280,12 +272,22 @@ watch(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
customerBranchFormState.value.currentCustomerId = route.params
|
||||||
|
.customerId as string;
|
||||||
|
await fetchList();
|
||||||
|
|
||||||
|
branch.value?.forEach((v) => {
|
||||||
|
currentBtnOpen.value.push(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FloatingActionButton
|
<FloatingActionButton
|
||||||
style="z-index: 999"
|
style="z-index: 999"
|
||||||
v-if="$route.name !== 'CustomerManagement'"
|
v-if="$route.name !== 'CustomerManagement' && canAccess('customer', 'edit')"
|
||||||
@click="openEmployerBranchForm('create')"
|
@click="openEmployerBranchForm('create')"
|
||||||
hide-icon
|
hide-icon
|
||||||
></FloatingActionButton>
|
></FloatingActionButton>
|
||||||
|
|
@ -473,7 +475,6 @@ watch(
|
||||||
<q-tr
|
<q-tr
|
||||||
:class="{
|
:class="{
|
||||||
'app-text-muted': props.row.status === 'INACTIVE',
|
'app-text-muted': props.row.status === 'INACTIVE',
|
||||||
'cursor-pointer': props.row._count?.branch !== 0,
|
|
||||||
}"
|
}"
|
||||||
:props="props"
|
:props="props"
|
||||||
@click="$emit('viewDetail', props.row, props.rowIndex)"
|
@click="$emit('viewDetail', props.row, props.rowIndex)"
|
||||||
|
|
@ -547,7 +548,13 @@ watch(
|
||||||
v-if="branchFieldSelected.includes('businessTypePure')"
|
v-if="branchFieldSelected.includes('businessTypePure')"
|
||||||
class="text-left"
|
class="text-left"
|
||||||
>
|
>
|
||||||
{{ useOptionStore().mapOption(props.row.businessType) || '-' }}
|
{{
|
||||||
|
props.row.businessType
|
||||||
|
? props.row.businessType[
|
||||||
|
$i18n.locale === 'eng' ? 'nameEN' : 'name'
|
||||||
|
]
|
||||||
|
: '-'
|
||||||
|
}}
|
||||||
</q-td>
|
</q-td>
|
||||||
<q-td
|
<q-td
|
||||||
v-if="branchFieldSelected.includes('totalEmployee')"
|
v-if="branchFieldSelected.includes('totalEmployee')"
|
||||||
|
|
@ -566,8 +573,6 @@ watch(
|
||||||
await fetchEmployee({
|
await fetchEmployee({
|
||||||
branchId: currentBranchEmployee,
|
branchId: currentBranchEmployee,
|
||||||
pageSize: 999,
|
pageSize: 999,
|
||||||
passport: true,
|
|
||||||
visa: true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
currentBtnOpen.map((v, i) => {
|
currentBtnOpen.map((v, i) => {
|
||||||
|
|
@ -615,7 +620,7 @@ watch(
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<TableEmpoloyee
|
<TableEmpoloyee
|
||||||
:prefix-id="props.row.registerName || props.row.firstName"
|
:prefix-id="props.row.registerName || props.row.firstName"
|
||||||
add-button
|
:add-button="canAccess('customer', 'edit')"
|
||||||
in-table
|
in-table
|
||||||
:list-employee="listEmployee"
|
:list-employee="listEmployee"
|
||||||
:columns-employee="columnsEmployee"
|
:columns-employee="columnsEmployee"
|
||||||
|
|
@ -638,10 +643,15 @@ watch(
|
||||||
"
|
"
|
||||||
@history="(item) => {}"
|
@history="(item) => {}"
|
||||||
@view="
|
@view="
|
||||||
(item) => {
|
async (item) => {
|
||||||
employeeFormState.drawerModal = true;
|
employeeFormState.drawerModal = true;
|
||||||
//employeeFormState.isEmployeeEdit = true;
|
//employeeFormState.isEmployeeEdit = true;
|
||||||
employeeFormStore.assignFormDataEmployee(item.id);
|
employeeFormStore.assignFormDataEmployee(item.id);
|
||||||
|
await fetchImageList(
|
||||||
|
item.id,
|
||||||
|
item.selectedImage || '',
|
||||||
|
'employee',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
|
@ -668,9 +678,11 @@ watch(
|
||||||
? `${props.row.addressEN || ''} ${props.row.subDistrict?.nameEN || ''} ${props.row.district?.nameEN || ''} ${props.row.province?.nameEN || ''}`
|
? `${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 || ''}`,
|
: `${props.row.address || ''} ${props.row.subDistrict?.name || ''} ${props.row.district?.name || ''} ${props.row.province?.name || ''}`,
|
||||||
telephone: props.row.telephoneNo,
|
telephone: props.row.telephoneNo,
|
||||||
businessTypePure: useOptionStore().mapOption(
|
businessTypePure: props.row.businessType
|
||||||
props.row.businessType,
|
? props.row.businessType[
|
||||||
),
|
$i18n.locale === 'eng' ? 'nameEN' : 'name'
|
||||||
|
]
|
||||||
|
: '-',
|
||||||
totalEmployee: props.row._count?.employee,
|
totalEmployee: props.row._count?.employee,
|
||||||
}"
|
}"
|
||||||
:visible-columns="branchFieldSelected"
|
:visible-columns="branchFieldSelected"
|
||||||
|
|
@ -759,7 +771,10 @@ watch(
|
||||||
/>
|
/>
|
||||||
<DeleteButton
|
<DeleteButton
|
||||||
icon-only
|
icon-only
|
||||||
v-if="customerBranchFormState.dialogType === 'info'"
|
v-if="
|
||||||
|
customerBranchFormState.dialogType === 'info' &&
|
||||||
|
canAccess('customer', 'edit')
|
||||||
|
"
|
||||||
@click="
|
@click="
|
||||||
() => {
|
() => {
|
||||||
deleteBranchById(customerBranchFormData.id || '');
|
deleteBranchById(customerBranchFormData.id || '');
|
||||||
|
|
@ -853,7 +868,6 @@ watch(
|
||||||
v-model:last-name-en="customerBranchFormData.lastNameEN"
|
v-model:last-name-en="customerBranchFormData.lastNameEN"
|
||||||
v-model:gender="customerBranchFormData.gender"
|
v-model:gender="customerBranchFormData.gender"
|
||||||
v-model:birth-date="customerBranchFormData.birthDate"
|
v-model:birth-date="customerBranchFormData.birthDate"
|
||||||
v-model:customer-name="customerBranchFormData.customerName"
|
|
||||||
v-model:legal-person-no="customerBranchFormData.legalPersonNo"
|
v-model:legal-person-no="customerBranchFormData.legalPersonNo"
|
||||||
v-model:branch-code="customerBranchFormData.code"
|
v-model:branch-code="customerBranchFormData.code"
|
||||||
v-model:register-name="customerBranchFormData.registerName"
|
v-model:register-name="customerBranchFormData.registerName"
|
||||||
|
|
@ -883,15 +897,14 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
<EmployerFormBusiness
|
<EmployerFormBusiness
|
||||||
dense
|
dense
|
||||||
class="q-mb-xl"
|
|
||||||
outlined
|
outlined
|
||||||
prefix-id="employer-branch"
|
prefix-id="employer-branch"
|
||||||
:readonly="customerBranchFormState.dialogType === 'info'"
|
:readonly="customerBranchFormState.dialogType === 'info'"
|
||||||
v-model:bussiness-type="customerBranchFormData.businessType"
|
v-model:business-type-id="customerBranchFormData.businessTypeId"
|
||||||
v-model:job-position="customerBranchFormData.jobPosition"
|
v-model:job-position="customerBranchFormData.jobPosition"
|
||||||
v-model:job-description="customerBranchFormData.jobDescription"
|
v-model:job-description="customerBranchFormData.jobDescription"
|
||||||
v-model:pay-date="customerBranchFormData.payDate"
|
v-model:pay-date="customerBranchFormData.payDate"
|
||||||
v-model:pay-date-e-n="customerBranchFormData.payDateEN"
|
v-model:pay-date-en="customerBranchFormData.payDateEN"
|
||||||
v-model:wage-rate="customerBranchFormData.wageRate"
|
v-model:wage-rate="customerBranchFormData.wageRate"
|
||||||
v-model:wage-rate-text="customerBranchFormData.wageRateText"
|
v-model:wage-rate-text="customerBranchFormData.wageRateText"
|
||||||
/>
|
/>
|
||||||
|
|
@ -982,7 +995,7 @@ watch(
|
||||||
v-model:email="customerBranchFormData.email"
|
v-model:email="customerBranchFormData.email"
|
||||||
v-model:contact-tel="customerBranchFormData.contactTel"
|
v-model:contact-tel="customerBranchFormData.contactTel"
|
||||||
v-model:office-tel="customerBranchFormData.officeTel"
|
v-model:office-tel="customerBranchFormData.officeTel"
|
||||||
v-model:agent="customerBranchFormData.agent"
|
v-model:agent-user-id="customerBranchFormData.agentUserId"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -998,6 +1011,18 @@ watch(
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</DialogFormContainer>
|
</DialogFormContainer>
|
||||||
|
|
||||||
|
<DialogEmployee
|
||||||
|
:fetch-list-employee="fetchEmployee"
|
||||||
|
:fetch-image-list="fetchImageList"
|
||||||
|
current-tab="employer"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DrawerEmployee
|
||||||
|
:fetch-list-employee="fetchEmployee"
|
||||||
|
:fetch-image-list="fetchImageList"
|
||||||
|
current-tab="employer"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
2078
src/pages/03_customer-management/TabCustomer.vue
Normal file
514
src/pages/03_customer-management/TabEmployee.vue
Normal file
|
|
@ -0,0 +1,514 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
|
||||||
|
import {
|
||||||
|
PaginationComponent,
|
||||||
|
PaginationPageSize,
|
||||||
|
ImageUploadDialog,
|
||||||
|
DialogForm,
|
||||||
|
NoData,
|
||||||
|
} from 'src/components';
|
||||||
|
import DialogEmployee from 'src/components/03_customer-management/DialogEmployee.vue';
|
||||||
|
import HistoryEditComponent from 'src/components/03_customer-management/HistoryEditComponent.vue';
|
||||||
|
import TableEmpoloyee from 'src/components/03_customer-management/TableEmpoloyee.vue';
|
||||||
|
import DrawerEmployee from 'src/components/03_customer-management/DrawerEmployee.vue';
|
||||||
|
|
||||||
|
import useFlowStore from 'src/stores/flow';
|
||||||
|
import useEmployeeStore from 'src/stores/employee';
|
||||||
|
import { Status } from 'src/stores/types';
|
||||||
|
import { Employee, EmployeeHistory } from 'src/stores/employee/types';
|
||||||
|
import { baseUrl, dialog, canAccess } from 'src/stores/utils';
|
||||||
|
import { calculateAge, toISOStringWithTimezone } from 'src/utils/datetime';
|
||||||
|
import { useCustomerForm, useEmployeeForm } from './form';
|
||||||
|
import { columnsEmployee } from './constant';
|
||||||
|
|
||||||
|
const $q = useQuasar();
|
||||||
|
const flowStore = useFlowStore();
|
||||||
|
const employeeStore = useEmployeeStore();
|
||||||
|
const employeeFormStore = useEmployeeForm();
|
||||||
|
const customerFormStore = useCustomerForm();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { state: employeeFormState, currentFromDataEmployee } =
|
||||||
|
storeToRefs(employeeFormStore);
|
||||||
|
const { deleteEmployeeById } = employeeFormStore;
|
||||||
|
const { state: customerFormState } = storeToRefs(customerFormStore);
|
||||||
|
|
||||||
|
const employeeStats = defineModel('employeeStats', { default: 0 });
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
currentTab: 'employee' | 'employer';
|
||||||
|
currentStatus: Status | 'All';
|
||||||
|
gridView: boolean;
|
||||||
|
inputSearch: string;
|
||||||
|
searchDate: string[];
|
||||||
|
fieldSelected: string[];
|
||||||
|
fetchImageList: (
|
||||||
|
id: string,
|
||||||
|
selectedName: string,
|
||||||
|
type: 'customer' | 'employee',
|
||||||
|
) => Promise<void>;
|
||||||
|
triggerChangeStatus: (
|
||||||
|
id: string,
|
||||||
|
status: string,
|
||||||
|
employeeName?: string,
|
||||||
|
) => void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
openSpecificEmployee,
|
||||||
|
fetchListEmployee,
|
||||||
|
toggleStatusEmployee,
|
||||||
|
});
|
||||||
|
|
||||||
|
const listEmployee = ref<Employee[]>([]);
|
||||||
|
const currentPageEmployee = ref<number>(1);
|
||||||
|
const maxPageEmployee = ref<number>(1);
|
||||||
|
const pageSize = ref<number>(30);
|
||||||
|
const employeeHistoryDialog = ref(false);
|
||||||
|
const employeeHistory = ref<EmployeeHistory[]>();
|
||||||
|
|
||||||
|
const splitPercent = computed(() => ($q.screen.lt.md ? 0 : 15));
|
||||||
|
|
||||||
|
async function fetchListEmployee(opt?: {
|
||||||
|
fetchStats?: boolean;
|
||||||
|
page?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
customerId?: string;
|
||||||
|
mobileFetch?: boolean;
|
||||||
|
}) {
|
||||||
|
const resultListEmployee = await employeeStore.fetchList({
|
||||||
|
customerId: opt?.customerId,
|
||||||
|
page: opt
|
||||||
|
? opt.mobileFetch
|
||||||
|
? 1
|
||||||
|
: opt.page || currentPageEmployee.value
|
||||||
|
: currentPageEmployee.value,
|
||||||
|
pageSize: opt
|
||||||
|
? opt.mobileFetch
|
||||||
|
? listEmployee.value.length +
|
||||||
|
(employeeStats.value === listEmployee.value.length ? 1 : 0)
|
||||||
|
: opt.pageSize || pageSize.value
|
||||||
|
: pageSize.value,
|
||||||
|
status:
|
||||||
|
props.currentStatus === 'All'
|
||||||
|
? undefined
|
||||||
|
: props.currentStatus === 'ACTIVE'
|
||||||
|
? 'ACTIVE'
|
||||||
|
: 'INACTIVE',
|
||||||
|
query: props.inputSearch,
|
||||||
|
passport: true,
|
||||||
|
visa: true,
|
||||||
|
startDate: props.searchDate[0],
|
||||||
|
endDate: props.searchDate[1],
|
||||||
|
});
|
||||||
|
if (resultListEmployee) {
|
||||||
|
maxPageEmployee.value = Math.ceil(
|
||||||
|
resultListEmployee.total / pageSize.value,
|
||||||
|
);
|
||||||
|
$q.screen.xs && !(opt && opt.mobileFetch)
|
||||||
|
? listEmployee.value.push(...resultListEmployee.result)
|
||||||
|
: (listEmployee.value = resultListEmployee.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt && opt.fetchStats)
|
||||||
|
employeeStats.value = await employeeStore.getStatsEmployee();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openHistory(id: string) {
|
||||||
|
const res = await employeeStore.getEditHistory(id);
|
||||||
|
employeeHistory.value = res.reverse();
|
||||||
|
employeeHistoryDialog.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function editEmployeeFormPersonal(id: string) {
|
||||||
|
await employeeFormStore.assignFormDataEmployee(id);
|
||||||
|
await props.fetchImageList(
|
||||||
|
id,
|
||||||
|
currentFromDataEmployee.value.selectedImage || '',
|
||||||
|
'employee',
|
||||||
|
);
|
||||||
|
|
||||||
|
employeeFormState.value.isEmployeeEdit = true;
|
||||||
|
employeeFormState.value.dialogType = 'edit';
|
||||||
|
employeeFormState.value.drawerModal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openSpecificEmployee(id: string) {
|
||||||
|
await employeeFormStore.assignFormDataEmployee(id);
|
||||||
|
await props.fetchImageList(
|
||||||
|
id,
|
||||||
|
currentFromDataEmployee.value.selectedImage || '',
|
||||||
|
'employee',
|
||||||
|
);
|
||||||
|
employeeFormState.value.dialogType = 'info';
|
||||||
|
employeeFormState.value.drawerModal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function toggleStatusEmployee(
|
||||||
|
id: string,
|
||||||
|
status: boolean,
|
||||||
|
employeeName: string,
|
||||||
|
) {
|
||||||
|
const res = await employeeStore.editById(id, {
|
||||||
|
status: !status ? 'ACTIVE' : 'INACTIVE',
|
||||||
|
firstNameEN: employeeName,
|
||||||
|
});
|
||||||
|
if (res && employeeFormState.value.drawerModal) {
|
||||||
|
currentFromDataEmployee.value.status = res.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
await employeeFormStore.assignFormDataEmployee(id);
|
||||||
|
await fetchListEmployee({ mobileFetch: $q.screen.xs });
|
||||||
|
flowStore.rotate();
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [
|
||||||
|
props.inputSearch,
|
||||||
|
props.searchDate,
|
||||||
|
props.currentStatus,
|
||||||
|
pageSize.value,
|
||||||
|
],
|
||||||
|
async () => {
|
||||||
|
currentPageEmployee.value = 1;
|
||||||
|
listEmployee.value = [];
|
||||||
|
await fetchListEmployee({ fetchStats: true });
|
||||||
|
|
||||||
|
customerFormState.value.currentCustomerId = undefined;
|
||||||
|
flowStore.rotate();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => employeeFormState.value.currentCustomerBranch,
|
||||||
|
(e) => {
|
||||||
|
if (!e) return;
|
||||||
|
if (employeeFormState.value.formDataEmployeeSameAddr) {
|
||||||
|
currentFromDataEmployee.value.address = e.address;
|
||||||
|
currentFromDataEmployee.value.addressEN = e.addressEN;
|
||||||
|
currentFromDataEmployee.value.provinceId = e.provinceId;
|
||||||
|
currentFromDataEmployee.value.districtId = e.districtId;
|
||||||
|
currentFromDataEmployee.value.subDistrictId = e.subDistrictId;
|
||||||
|
}
|
||||||
|
currentFromDataEmployee.value.customerBranchId = e.id;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => employeeFormState.value.formDataEmployeeSameAddr,
|
||||||
|
(isSame) => {
|
||||||
|
if (!employeeFormState.value.currentCustomerBranch) return;
|
||||||
|
if (isSame) {
|
||||||
|
currentFromDataEmployee.value.address =
|
||||||
|
employeeFormState.value.currentCustomerBranch.address;
|
||||||
|
currentFromDataEmployee.value.addressEN =
|
||||||
|
employeeFormState.value.currentCustomerBranch.addressEN;
|
||||||
|
currentFromDataEmployee.value.provinceId =
|
||||||
|
employeeFormState.value.currentCustomerBranch.provinceId;
|
||||||
|
currentFromDataEmployee.value.districtId =
|
||||||
|
employeeFormState.value.currentCustomerBranch.districtId;
|
||||||
|
currentFromDataEmployee.value.subDistrictId =
|
||||||
|
employeeFormState.value.currentCustomerBranch.subDistrictId;
|
||||||
|
}
|
||||||
|
currentFromDataEmployee.value.customerBranchId =
|
||||||
|
employeeFormState.value.currentCustomerBranch.id;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => currentFromDataEmployee.value.dateOfBirth,
|
||||||
|
(v) => {
|
||||||
|
const isEdit =
|
||||||
|
employeeFormState.value.drawerModal &&
|
||||||
|
employeeFormState.value.isEmployeeEdit;
|
||||||
|
let currentFormDate = v && toISOStringWithTimezone(new Date(v));
|
||||||
|
let currentDate: string = '';
|
||||||
|
|
||||||
|
if (isEdit && employeeFormState.value.currentEmployee) {
|
||||||
|
currentDate = toISOStringWithTimezone(
|
||||||
|
new Date(employeeFormState.value.currentEmployee.dateOfBirth),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
employeeFormState.value.dialogModal ||
|
||||||
|
(isEdit && currentFormDate !== currentDate)
|
||||||
|
) {
|
||||||
|
const age = calculateAge(
|
||||||
|
currentFromDataEmployee.value.dateOfBirth,
|
||||||
|
'year',
|
||||||
|
);
|
||||||
|
if (currentFromDataEmployee.value.dateOfBirth && Number(age) < 15) {
|
||||||
|
dialog({
|
||||||
|
color: 'warning',
|
||||||
|
icon: 'mdi-alert',
|
||||||
|
title: t('dialog.title.youngWorker15'),
|
||||||
|
cancelText: t('general.edit'),
|
||||||
|
persistent: true,
|
||||||
|
message: t('dialog.message.youngWorker15'),
|
||||||
|
|
||||||
|
cancel: async () => {
|
||||||
|
currentFromDataEmployee.value.dateOfBirth = null;
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
currentFromDataEmployee.value.dateOfBirth &&
|
||||||
|
Number(age) > 15 &&
|
||||||
|
Number(age) <= 18
|
||||||
|
) {
|
||||||
|
dialog({
|
||||||
|
color: 'warning',
|
||||||
|
icon: 'mdi-alert',
|
||||||
|
title: t('dialog.title.youngWorker18'),
|
||||||
|
cancelText: t('general.cancel'),
|
||||||
|
actionText: t('general.confirm'),
|
||||||
|
persistent: true,
|
||||||
|
message: t('dialog.message.youngWorker18'),
|
||||||
|
action: () => {},
|
||||||
|
cancel: async () => {
|
||||||
|
currentFromDataEmployee.value.dateOfBirth = null;
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => currentFromDataEmployee.value.image,
|
||||||
|
() => {
|
||||||
|
if (currentFromDataEmployee.value.image !== null)
|
||||||
|
employeeFormState.value.isImageEdit = true;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
currentPageEmployee.value = 1;
|
||||||
|
listEmployee.value = [];
|
||||||
|
await fetchListEmployee({ fetchStats: true });
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<q-splitter
|
||||||
|
v-model="splitPercent"
|
||||||
|
:limits="[0, 100]"
|
||||||
|
class="col full-width"
|
||||||
|
before-class="overflow-hidden"
|
||||||
|
after-class="overflow-hidden"
|
||||||
|
:disable="$q.screen.lt.sm"
|
||||||
|
>
|
||||||
|
<template v-slot:before>
|
||||||
|
<div
|
||||||
|
class="column q-pa-md surface-1 full-height full-width"
|
||||||
|
style="gap: var(--size-1)"
|
||||||
|
>
|
||||||
|
<q-item
|
||||||
|
active
|
||||||
|
dense
|
||||||
|
active-class="employer-active"
|
||||||
|
class="no-padding items-center rounded full-width"
|
||||||
|
v-close-popup
|
||||||
|
clickable
|
||||||
|
>
|
||||||
|
<span class="q-px-md ellipsis">
|
||||||
|
{{ $t('general.all') }}
|
||||||
|
</span>
|
||||||
|
</q-item>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:after>
|
||||||
|
<div class="column full-height no-wrap">
|
||||||
|
<!-- employee -->
|
||||||
|
<template
|
||||||
|
v-if="listEmployee && employeeStats > 0 && currentTab === 'employee'"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="listEmployee.length === 0"
|
||||||
|
class="row col full-width items-center justify-center"
|
||||||
|
style="min-height: 250px"
|
||||||
|
>
|
||||||
|
<NoData :not-found="!!inputSearch" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<article
|
||||||
|
v-if="listEmployee.length !== 0"
|
||||||
|
class="column scroll q-pa-md col"
|
||||||
|
>
|
||||||
|
<q-infinite-scroll
|
||||||
|
:offset="10"
|
||||||
|
@load="
|
||||||
|
(_, done) => {
|
||||||
|
if (
|
||||||
|
$q.screen.gt.xs ||
|
||||||
|
currentPageEmployee === maxPageEmployee
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
currentPageEmployee = currentPageEmployee + 1;
|
||||||
|
fetchListEmployee().then(() =>
|
||||||
|
done(currentPageEmployee >= maxPageEmployee),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<TableEmpoloyee
|
||||||
|
:hide-delete="!canAccess('customer', 'edit')"
|
||||||
|
v-model:page-size="pageSize"
|
||||||
|
v-model:current-page="currentPageEmployee"
|
||||||
|
:grid-view="gridView"
|
||||||
|
:list-employee="listEmployee"
|
||||||
|
:columns-employee="columnsEmployee"
|
||||||
|
:field-selected="fieldSelected"
|
||||||
|
@history="
|
||||||
|
(item: any) => {
|
||||||
|
openHistory(item.id);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
@view="
|
||||||
|
async (item: any) => {
|
||||||
|
employeeFormState.drawerModal = true;
|
||||||
|
employeeFormState.isEmployeeEdit = false;
|
||||||
|
employeeFormStore.assignFormDataEmployee(item.id);
|
||||||
|
await fetchImageList(
|
||||||
|
item.id,
|
||||||
|
item.selectedImage || '',
|
||||||
|
'employee',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
@edit="(item: any) => editEmployeeFormPersonal(item.id)"
|
||||||
|
@delete="
|
||||||
|
(item: any) => {
|
||||||
|
deleteEmployeeById({
|
||||||
|
id: item.id,
|
||||||
|
fetch: async () =>
|
||||||
|
await fetchListEmployee(
|
||||||
|
currentTab === 'employer'
|
||||||
|
? {
|
||||||
|
page: 1,
|
||||||
|
pageSize: 999,
|
||||||
|
customerId: customerFormState.currentCustomerId,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
fetchStats: true,
|
||||||
|
mobileFetch: $q.screen.xs,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
"
|
||||||
|
@toggle-status="
|
||||||
|
async (item: any) => {
|
||||||
|
triggerChangeStatus(item.id, item.status, item.firstNameEN);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<template v-slot:loading>
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
$q.screen.lt.sm && currentPageEmployee !== maxPageEmployee
|
||||||
|
"
|
||||||
|
class="row justify-center"
|
||||||
|
>
|
||||||
|
<q-spinner-dots color="primary" size="40px" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-infinite-scroll>
|
||||||
|
</article>
|
||||||
|
<footer
|
||||||
|
v-if="listEmployee.length !== 0 && $q.screen.gt.xs"
|
||||||
|
class="row justify-between items-center q-px-md q-py-sm"
|
||||||
|
>
|
||||||
|
<div class="row col-4 items-center">
|
||||||
|
<div
|
||||||
|
class="app-text-muted"
|
||||||
|
style="width: 80px"
|
||||||
|
v-if="$q.screen.gt.sm"
|
||||||
|
>
|
||||||
|
{{ $t('general.recordPerPage') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div><PaginationPageSize v-model="pageSize" /></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-4 flex justify-center app-text-muted">
|
||||||
|
{{
|
||||||
|
$q.screen.gt.sm
|
||||||
|
? $t('general.recordsPage', {
|
||||||
|
resultcurrentPage: listEmployee.length,
|
||||||
|
total: employeeStats,
|
||||||
|
})
|
||||||
|
: $t('general.ofPage', {
|
||||||
|
current: listEmployee.length,
|
||||||
|
total: employeeStats,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-4 flex justify-end">
|
||||||
|
<PaginationComponent
|
||||||
|
v-model:current-page="currentPageEmployee"
|
||||||
|
v-model:max-page="maxPageEmployee"
|
||||||
|
:fetch-data="
|
||||||
|
async () => {
|
||||||
|
await fetchListEmployee();
|
||||||
|
flowStore.rotate();
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-splitter>
|
||||||
|
|
||||||
|
<!-- add employee -->
|
||||||
|
<DialogEmployee
|
||||||
|
:fetch-list-employee="fetchListEmployee"
|
||||||
|
:fetch-image-list="fetchImageList"
|
||||||
|
:current-tab="currentTab"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- ลูกจ้าง edit employee -->
|
||||||
|
<DrawerEmployee
|
||||||
|
:fetch-list-employee="fetchListEmployee"
|
||||||
|
:fetch-image-list="fetchImageList"
|
||||||
|
:current-tab="currentTab"
|
||||||
|
@change-status="
|
||||||
|
(s) =>
|
||||||
|
triggerChangeStatus(
|
||||||
|
currentFromDataEmployee.id,
|
||||||
|
s,
|
||||||
|
currentFromDataEmployee.firstNameEN,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DialogForm
|
||||||
|
:title="$t('general.historyEdit')"
|
||||||
|
hide-footer
|
||||||
|
v-model:modal="employeeHistoryDialog"
|
||||||
|
>
|
||||||
|
<div class="q-pa-md">
|
||||||
|
<HistoryEditComponent
|
||||||
|
v-if="employeeHistory"
|
||||||
|
v-model:history-list="employeeHistory"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</DialogForm>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.employer-active {
|
||||||
|
background-color: hsla(var(--info-bg) / 0.1);
|
||||||
|
color: hsl(var(--info-bg));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -140,7 +140,7 @@ watch(
|
||||||
:rules="[
|
:rules="[
|
||||||
(val) => !!val || $t('form.error.required'),
|
(val) => !!val || $t('form.error.required'),
|
||||||
(val) =>
|
(val) =>
|
||||||
/^[A-Za-z0-9ก-๙\s&.,'-]+$/.test(val) ||
|
/^[A-Za-z0-9ก-๙\s&.,'()-]+$/.test(val) ||
|
||||||
$t('form.error.branchNameField'),
|
$t('form.error.branchNameField'),
|
||||||
]"
|
]"
|
||||||
/>
|
/>
|
||||||
|
|
@ -167,20 +167,6 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12 row q-col-gutter-sm">
|
<div class="col-12 row q-col-gutter-sm">
|
||||||
<q-input
|
|
||||||
dense
|
|
||||||
outlined
|
|
||||||
:readonly="readonly"
|
|
||||||
hide-bottom-space
|
|
||||||
class="col-12 col-md-5"
|
|
||||||
:label="$t('customer.form.employerName')"
|
|
||||||
for="input-legal-person-no"
|
|
||||||
:model-value="customerName"
|
|
||||||
@update:model-value="
|
|
||||||
(v) => (typeof v === 'string' ? (customerName = v.trim()) : '')
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<q-input
|
<q-input
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
|
|
@ -350,6 +336,7 @@ watch(
|
||||||
(v) => (typeof v === 'string' ? (prefixName = v) : '')
|
(v) => (typeof v === 'string' ? (prefixName = v) : '')
|
||||||
"
|
"
|
||||||
@clear="prefixName = ''"
|
@clear="prefixName = ''"
|
||||||
|
:rules="[(val: string) => !!val || $t('form.error.required')]"
|
||||||
>
|
>
|
||||||
<template v-slot:no-option>
|
<template v-slot:no-option>
|
||||||
<q-item>
|
<q-item>
|
||||||
|
|
@ -401,8 +388,8 @@ watch(
|
||||||
label="Prefix"
|
label="Prefix"
|
||||||
:model-value="
|
:model-value="
|
||||||
readonly
|
readonly
|
||||||
? capitalize(prefixName || '') || '-'
|
? prefixName.toUpperCase() || '-'
|
||||||
: capitalize(prefixName || '')
|
: prefixName.toUpperCase() || ''
|
||||||
"
|
"
|
||||||
@update:model-value="
|
@update:model-value="
|
||||||
(v) => (typeof v === 'string' ? (prefixName = v) : '')
|
(v) => (typeof v === 'string' ? (prefixName = v) : '')
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import useOptionStore from 'stores/options';
|
import useOptionStore from 'stores/options';
|
||||||
import SelectBranch from 'src/components/shared/select/SelectBranch.vue';
|
import SelectBranch from 'src/components/shared/select/SelectBranch.vue';
|
||||||
import { isRoleInclude } from 'src/stores/utils';
|
import { isRoleInclude } from 'src/stores/utils';
|
||||||
|
import SelectBusinessType from 'src/components/shared/select/SelectBusinessType.vue';
|
||||||
|
|
||||||
withDefaults(
|
withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
|
@ -102,7 +103,13 @@ const telephoneNo = defineModel<string>('telephoneNo', { default: '' });
|
||||||
class="col-md-6"
|
class="col-md-6"
|
||||||
:readonly
|
:readonly
|
||||||
:disabled="
|
:disabled="
|
||||||
!isRoleInclude(['admin', 'system', 'head_of_admin']) && !readonly
|
!isRoleInclude([
|
||||||
|
'admin',
|
||||||
|
'system',
|
||||||
|
'head_of_admin',
|
||||||
|
'executive',
|
||||||
|
'accountant',
|
||||||
|
]) && !readonly
|
||||||
"
|
"
|
||||||
:label="$t('customer.form.registeredBranch')"
|
:label="$t('customer.form.registeredBranch')"
|
||||||
select-first-value
|
select-first-value
|
||||||
|
|
@ -136,15 +143,10 @@ const telephoneNo = defineModel<string>('telephoneNo', { default: '' });
|
||||||
for="input-tax"
|
for="input-tax"
|
||||||
v-model="legalPersonNo"
|
v-model="legalPersonNo"
|
||||||
/>
|
/>
|
||||||
<q-input
|
<SelectBusinessType
|
||||||
dense
|
|
||||||
outlined
|
|
||||||
:readonly="readonly"
|
|
||||||
hide-bottom-space
|
|
||||||
class="col-6 col-md-3"
|
class="col-6 col-md-3"
|
||||||
:label="$t('customer.table.businessTypePure')"
|
v-model:value="businessType"
|
||||||
for="input-business-type"
|
:readonly
|
||||||
:model-value="optionStore.mapOption(businessType)"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -173,15 +175,10 @@ const telephoneNo = defineModel<string>('telephoneNo', { default: '' });
|
||||||
:label="$t('personnel.form.citizenId')"
|
:label="$t('personnel.form.citizenId')"
|
||||||
for="input-citizen-id"
|
for="input-citizen-id"
|
||||||
/>
|
/>
|
||||||
<q-input
|
<SelectBusinessType
|
||||||
dense
|
|
||||||
outlined
|
|
||||||
:readonly="readonly"
|
|
||||||
hide-bottom-space
|
|
||||||
class="col-6 col-md-3"
|
class="col-6 col-md-3"
|
||||||
:label="$t('customer.table.businessTypePure')"
|
v-model:value="businessType"
|
||||||
for="input-first-name-en"
|
:readonly
|
||||||
:model-value="optionStore.mapOption(businessType)"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import { CustomerCreate } from 'stores/customer/types';
|
||||||
import EmployerFormAbout from './EmployerFormAbout.vue';
|
import EmployerFormAbout from './EmployerFormAbout.vue';
|
||||||
import EmployerFormAuthorized from './EmployerFormAuthorized.vue';
|
import EmployerFormAuthorized from './EmployerFormAuthorized.vue';
|
||||||
import { waitAll } from 'src/stores/utils';
|
import { waitAll } from 'src/stores/utils';
|
||||||
|
import FormEmployeePassport from 'src/components/03_customer-management/FormEmployeePassport.vue';
|
||||||
|
import FormEmployeeVisa from 'src/components/03_customer-management/FormEmployeeVisa.vue';
|
||||||
import {
|
import {
|
||||||
FormCitizen,
|
FormCitizen,
|
||||||
CorpFormBusinessRegistration,
|
CorpFormBusinessRegistration,
|
||||||
|
|
@ -51,6 +53,7 @@ withDefaults(
|
||||||
actionDisabled?: boolean;
|
actionDisabled?: boolean;
|
||||||
customerType?: 'CORP' | 'PERS';
|
customerType?: 'CORP' | 'PERS';
|
||||||
hideAction?: boolean;
|
hideAction?: boolean;
|
||||||
|
hideDelete?: boolean;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
hideAction: false,
|
hideAction: false,
|
||||||
|
|
@ -81,7 +84,7 @@ withDefaults(
|
||||||
/>
|
/>
|
||||||
<DeleteButton
|
<DeleteButton
|
||||||
icon-only
|
icon-only
|
||||||
v-if="readonly"
|
v-if="readonly && !hideDelete"
|
||||||
@click="$emit('delete')"
|
@click="$emit('delete')"
|
||||||
type="button"
|
type="button"
|
||||||
:disabled="actionDisabled"
|
:disabled="actionDisabled"
|
||||||
|
|
@ -141,7 +144,6 @@ withDefaults(
|
||||||
v-model:last-name-en="item.lastNameEN"
|
v-model:last-name-en="item.lastNameEN"
|
||||||
v-model:gender="item.gender"
|
v-model:gender="item.gender"
|
||||||
v-model:birth-date="item.birthDate"
|
v-model:birth-date="item.birthDate"
|
||||||
v-model:customer-name="item.customerName"
|
|
||||||
v-model:legal-person-no="item.legalPersonNo"
|
v-model:legal-person-no="item.legalPersonNo"
|
||||||
v-model:branch-code="item.code"
|
v-model:branch-code="item.code"
|
||||||
v-model:register-name="item.registerName"
|
v-model:register-name="item.registerName"
|
||||||
|
|
@ -158,7 +160,7 @@ withDefaults(
|
||||||
outlined
|
outlined
|
||||||
:prefix-id="prefixId || 'employer'"
|
:prefix-id="prefixId || 'employer'"
|
||||||
:readonly="readonly"
|
:readonly="readonly"
|
||||||
v-model:bussiness-type="item.businessType"
|
v-model:business-type-id="item.businessTypeId"
|
||||||
v-model:job-position="item.jobPosition"
|
v-model:job-position="item.jobPosition"
|
||||||
v-model:job-description="item.jobDescription"
|
v-model:job-description="item.jobDescription"
|
||||||
v-model:pay-date="item.payDate"
|
v-model:pay-date="item.payDate"
|
||||||
|
|
@ -220,7 +222,6 @@ withDefaults(
|
||||||
hide-action
|
hide-action
|
||||||
:ocr="
|
:ocr="
|
||||||
async (group, file) => {
|
async (group, file) => {
|
||||||
console.log(group);
|
|
||||||
if (group !== 'attachment') {
|
if (group !== 'attachment') {
|
||||||
const res = await ocrStore.sendOcr({
|
const res = await ocrStore.sendOcr({
|
||||||
file: file,
|
file: file,
|
||||||
|
|
@ -245,12 +246,20 @@ withDefaults(
|
||||||
:auto-save="item.id !== ''"
|
:auto-save="item.id !== ''"
|
||||||
:download="
|
:download="
|
||||||
(obj) => {
|
(obj) => {
|
||||||
customerStore.getFile({
|
if (obj.group === 'citizen') {
|
||||||
parentId: item.id || '',
|
customerStore.getFile({
|
||||||
group: obj.group,
|
parentId: item.id || '',
|
||||||
fileId: obj._meta.id,
|
group: obj.group,
|
||||||
download: true,
|
fileId: obj._meta.id,
|
||||||
});
|
download: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
customerStore.getAttachment({
|
||||||
|
parentId: item.id || '',
|
||||||
|
name: obj._meta.id,
|
||||||
|
download: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
:delete-item="
|
:delete-item="
|
||||||
|
|
@ -279,7 +288,7 @@ withDefaults(
|
||||||
_meta: any,
|
_meta: any,
|
||||||
file: File | undefined,
|
file: File | undefined,
|
||||||
) => {
|
) => {
|
||||||
if (group !== 'attachment') {
|
if (group === 'citizen') {
|
||||||
if (file !== undefined && item.id) {
|
if (file !== undefined && item.id) {
|
||||||
const res = await customerStore.postMeta({
|
const res = await customerStore.postMeta({
|
||||||
parentId: item.id || '',
|
parentId: item.id || '',
|
||||||
|
|
@ -347,7 +356,6 @@ withDefaults(
|
||||||
});
|
});
|
||||||
|
|
||||||
const tempValue = resMeta.map(async (v: any) => {
|
const tempValue = resMeta.map(async (v: any) => {
|
||||||
console.log(v.expireDate);
|
|
||||||
return {
|
return {
|
||||||
_meta: { ...v },
|
_meta: { ...v },
|
||||||
name: `${group}-${dateFormat(v.expireDate)}`,
|
name: `${group}-${dateFormat(v.expireDate)}`,
|
||||||
|
|
@ -368,7 +376,6 @@ withDefaults(
|
||||||
});
|
});
|
||||||
|
|
||||||
const tempValue = (res as string[]).map(async (i: any) => {
|
const tempValue = (res as string[]).map(async (i: any) => {
|
||||||
console.log(i);
|
|
||||||
return {
|
return {
|
||||||
_meta: { id: i, name: i },
|
_meta: { id: i, name: i },
|
||||||
name: i || '',
|
name: i || '',
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,28 @@ import { onMounted, watch } from 'vue';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import ThaiBahtText from 'thai-baht-text';
|
import ThaiBahtText from 'thai-baht-text';
|
||||||
|
import SelectBusinessType from 'src/components/shared/select/SelectBusinessType.vue';
|
||||||
|
|
||||||
|
import BusinessTypeDialog from 'src/pages/16_business-type-management/BusinessTypeDialog.vue';
|
||||||
|
|
||||||
|
import useBusinessTypeStore from 'src/stores/business-type';
|
||||||
|
|
||||||
const { locale } = useI18n({ useScope: 'global' });
|
const { locale } = useI18n({ useScope: 'global' });
|
||||||
|
|
||||||
const rawOption = ref();
|
const rawOption = ref();
|
||||||
|
|
||||||
const bussinessType = defineModel<string>('bussinessType');
|
const businessTypeDialog = ref<boolean>(false);
|
||||||
|
const formDataBusinessType = ref<{
|
||||||
|
name: string;
|
||||||
|
nameEN: string;
|
||||||
|
}>({
|
||||||
|
name: '',
|
||||||
|
nameEN: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const useBusinessType = useBusinessTypeStore();
|
||||||
|
|
||||||
|
const businessTypeId = defineModel<string>('businessTypeId');
|
||||||
const jobPosition = defineModel<string>('jobPosition');
|
const jobPosition = defineModel<string>('jobPosition');
|
||||||
const jobDescription = defineModel<string>('jobDescription');
|
const jobDescription = defineModel<string>('jobDescription');
|
||||||
const payDate = defineModel<string>('payDate');
|
const payDate = defineModel<string>('payDate');
|
||||||
|
|
@ -28,6 +44,8 @@ const typeBusinessENOption = ref([]);
|
||||||
const jobPositionOption = ref([]);
|
const jobPositionOption = ref([]);
|
||||||
const jobPositionENOption = ref([]);
|
const jobPositionENOption = ref([]);
|
||||||
|
|
||||||
|
const keySelect = ref<number>(0);
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
title?: string;
|
title?: string;
|
||||||
dense?: boolean;
|
dense?: boolean;
|
||||||
|
|
@ -37,35 +55,33 @@ defineProps<{
|
||||||
showTitle?: boolean;
|
showTitle?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
function resetFormBusinessType() {
|
||||||
|
businessTypeDialog.value = false;
|
||||||
|
formDataBusinessType.value = { name: '', nameEN: '' };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submitBusinessType() {
|
||||||
|
const res = await useBusinessType.create(formDataBusinessType.value);
|
||||||
|
if (res) {
|
||||||
|
businessTypeId.value = res.id;
|
||||||
|
resetFormBusinessType();
|
||||||
|
keySelect.value++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const resultOption = await fetch('/option/option.json');
|
const resultOption = await fetch('/option/option.json');
|
||||||
rawOption.value = await resultOption.json();
|
rawOption.value = await resultOption.json();
|
||||||
typeBusinessENOption.value = rawOption.value.eng.businessType;
|
|
||||||
jobPositionENOption.value = rawOption.value.eng.position;
|
jobPositionENOption.value = rawOption.value.eng.position;
|
||||||
|
|
||||||
if (locale.value === 'eng') {
|
if (locale.value === 'eng') {
|
||||||
typeBusinessOption.value = rawOption.value.eng.businessType;
|
|
||||||
jobPositionOption.value = rawOption.value.eng.position;
|
jobPositionOption.value = rawOption.value.eng.position;
|
||||||
}
|
}
|
||||||
if (locale.value === 'tha') {
|
if (locale.value === 'tha') {
|
||||||
typeBusinessOption.value = rawOption.value.tha.businessType;
|
|
||||||
jobPositionOption.value = rawOption.value.tha.position;
|
jobPositionOption.value = rawOption.value.tha.position;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
watch([typeBusinessOption, typeBusinessENOption], () => {
|
|
||||||
typeBusinessFilter = selectFilterOptionRefMod(
|
|
||||||
typeBusinessOption,
|
|
||||||
typeBusinessOptions,
|
|
||||||
'label',
|
|
||||||
);
|
|
||||||
typeBusinessENFilter = selectFilterOptionRefMod(
|
|
||||||
typeBusinessENOption,
|
|
||||||
typeBusinessENOptions,
|
|
||||||
'label',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => rate.value,
|
() => rate.value,
|
||||||
(newValue) => {
|
(newValue) => {
|
||||||
|
|
@ -135,69 +151,26 @@ let jobPositionENFilter = selectFilterOptionRefMod(
|
||||||
<span>{{ $t('customerBranch.tab.business') }}</span>
|
<span>{{ $t('customerBranch.tab.business') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-select
|
<SelectBusinessType
|
||||||
outlined
|
:key="keySelect"
|
||||||
clearable
|
|
||||||
use-input
|
|
||||||
fill-input
|
|
||||||
emit-value
|
|
||||||
map-options
|
|
||||||
hide-selected
|
|
||||||
hide-bottom-space
|
|
||||||
:hide-dropdown-icon="readonly"
|
|
||||||
input-debounce="0"
|
|
||||||
option-value="value"
|
|
||||||
option-label="label"
|
|
||||||
v-model="bussinessType"
|
|
||||||
class="col-md-6 col-12"
|
class="col-md-6 col-12"
|
||||||
:dense="dense"
|
v-model:value="businessTypeId"
|
||||||
:readonly="readonly"
|
:readonly
|
||||||
:label="$t('customer.form.businessType')"
|
creatable
|
||||||
:options="typeBusinessOptions"
|
lang="tha"
|
||||||
:for="`${prefixId}-select-business-type`"
|
|
||||||
@filter="typeBusinessFilter"
|
|
||||||
:rules="[(val: string) => !!val || $t('form.error.required')]"
|
:rules="[(val: string) => !!val || $t('form.error.required')]"
|
||||||
>
|
@create="() => (businessTypeDialog = true)"
|
||||||
<template v-slot:no-option>
|
/>
|
||||||
<q-item>
|
<SelectBusinessType
|
||||||
<q-item-section class="text-grey">
|
:key="keySelect"
|
||||||
{{ $t('general.noData') }}
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</template>
|
|
||||||
</q-select>
|
|
||||||
<q-select
|
|
||||||
:for="`${prefixId}-input-bussiness-type-en`"
|
|
||||||
:id="`${prefixId}-input-bussiness-type-en`"
|
|
||||||
:label="`${$t('customer.form.businessType')} (EN)`"
|
|
||||||
outlined
|
|
||||||
clearable
|
|
||||||
use-input
|
|
||||||
fill-input
|
|
||||||
emit-value
|
|
||||||
map-options
|
|
||||||
hide-selected
|
|
||||||
hide-bottom-space
|
|
||||||
:hide-dropdown-icon="readonly"
|
|
||||||
input-debounce="0"
|
|
||||||
option-value="value"
|
|
||||||
option-label="label"
|
|
||||||
v-model="bussinessType"
|
|
||||||
class="col-md-6 col-12"
|
class="col-md-6 col-12"
|
||||||
:dense="dense"
|
v-model:value="businessTypeId"
|
||||||
:readonly="readonly"
|
:readonly
|
||||||
:options="typeBusinessENOptions"
|
creatable
|
||||||
@filter="typeBusinessENFilter"
|
lang="eng"
|
||||||
:rules="[(val: string) => !!val || $t('form.error.required')]"
|
:rules="[(val: string) => !!val || $t('form.error.required')]"
|
||||||
>
|
@create="() => (businessTypeDialog = true)"
|
||||||
<template v-slot:no-option>
|
/>
|
||||||
<q-item>
|
|
||||||
<q-item-section class="text-grey">
|
|
||||||
{{ $t('general.noData') }}
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</template>
|
|
||||||
</q-select>
|
|
||||||
|
|
||||||
<q-select
|
<q-select
|
||||||
outlined
|
outlined
|
||||||
|
|
@ -348,4 +321,12 @@ let jobPositionENFilter = selectFilterOptionRefMod(
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<BusinessTypeDialog
|
||||||
|
ref="refBusinessTypeDialog"
|
||||||
|
@close="resetFormBusinessType()"
|
||||||
|
@submit="submitBusinessType()"
|
||||||
|
v-model="businessTypeDialog"
|
||||||
|
v-model:data="formDataBusinessType"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,6 @@ const contactName = defineModel<string>('contactName');
|
||||||
const email = defineModel<string>('email');
|
const email = defineModel<string>('email');
|
||||||
const contactTel = defineModel<string>('contactTel');
|
const contactTel = defineModel<string>('contactTel');
|
||||||
const officeTel = defineModel<string>('officeTel');
|
const officeTel = defineModel<string>('officeTel');
|
||||||
const agent = defineModel<string>('agent');
|
|
||||||
|
|
||||||
const agentUserId = defineModel<string>('agentUserId');
|
const agentUserId = defineModel<string>('agentUserId');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -109,7 +107,6 @@ const agentUserId = defineModel<string>('agentUserId');
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
||||||
<SelectAgent
|
<SelectAgent
|
||||||
:label="$t('customer.form.agent')"
|
:label="$t('customer.form.agent')"
|
||||||
v-model:value="agentUserId"
|
v-model:value="agentUserId"
|
||||||
|
|
|
||||||
|
|
@ -69,19 +69,19 @@ export const uploadFileListCustomer: {
|
||||||
}[] = [
|
}[] = [
|
||||||
{
|
{
|
||||||
label: 'customer.typeFile.citizenId',
|
label: 'customer.typeFile.citizenId',
|
||||||
value: 'citizen',
|
|
||||||
group: 'citizen',
|
group: 'citizen',
|
||||||
|
value: 'citizen',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'customer.typeFile.registrationBook',
|
label: 'customer.typeFile.registrationBook',
|
||||||
value: 'attachment',
|
|
||||||
group: 'houseRegistration',
|
group: 'houseRegistration',
|
||||||
|
value: 'attachment',
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
label: 'customer.typeFile.houseMap',
|
label: 'customer.typeFile.houseMap',
|
||||||
value: 'attachment',
|
|
||||||
group: 'vatRegistration',
|
group: 'vatRegistration',
|
||||||
|
value: 'attachment',
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -92,7 +92,7 @@ export const uploadFileListCustomer: {
|
||||||
|
|
||||||
{
|
{
|
||||||
label: 'customer.typeFile.dbdCertificate',
|
label: 'customer.typeFile.dbdCertificate',
|
||||||
group: 'powerOfAttorney',
|
group: 'dbdCertificate',
|
||||||
value: 'attachment',
|
value: 'attachment',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -144,43 +144,43 @@ export const uploadFileListEmployee: {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'customerEmployee.fileType.tm6',
|
label: 'customerEmployee.fileType.tm6',
|
||||||
value: 'attachment',
|
|
||||||
group: 'tm6',
|
group: 'tm6',
|
||||||
|
value: 'attachment',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'customerEmployee.fileType.workPermit',
|
label: 'customerEmployee.fileType.workPermit',
|
||||||
value: 'attachment',
|
|
||||||
group: 'workPermit',
|
group: 'workPermit',
|
||||||
|
value: 'attachment',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'customerEmployee.fileType.noticeJobEmployment',
|
label: 'customerEmployee.fileType.noticeJobEmployment',
|
||||||
value: 'attachment',
|
|
||||||
group: 'noticeJobEmployment',
|
group: 'noticeJobEmployment',
|
||||||
|
value: 'attachment',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'customerEmployee.fileType.noticeJobEntry',
|
label: 'customerEmployee.fileType.noticeJobEntry',
|
||||||
value: 'attachment',
|
|
||||||
group: 'noticeJobEntry',
|
group: 'noticeJobEntry',
|
||||||
|
value: 'attachment',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'customerEmployee.fileType.historyJob',
|
label: 'customerEmployee.fileType.historyJob',
|
||||||
value: 'attachment',
|
|
||||||
group: 'historyJob',
|
group: 'historyJob',
|
||||||
|
value: 'attachment',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'customerEmployee.fileType.acceptJob',
|
label: 'customerEmployee.fileType.acceptJob',
|
||||||
value: 'attachment',
|
|
||||||
group: 'acceptJob',
|
group: 'acceptJob',
|
||||||
|
value: 'attachment',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'customerEmployee.fileType.receipt',
|
label: 'customerEmployee.fileType.receipt',
|
||||||
value: 'attachment',
|
|
||||||
group: 'receipt',
|
group: 'receipt',
|
||||||
|
value: 'attachment',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'customerEmployee.fileType.other',
|
label: 'customerEmployee.fileType.other',
|
||||||
value: 'attachment',
|
|
||||||
group: 'other',
|
group: 'other',
|
||||||
|
value: 'attachment',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
export const useCustomerForm = defineStore('form-customer', () => {
|
export const useCustomerForm = defineStore('form-customer', () => {
|
||||||
const customerStore = useCustomerStore();
|
const customerStore = useCustomerStore();
|
||||||
|
const onCreateImageList = ref<{
|
||||||
|
selectedImage: string;
|
||||||
|
list: { url: string; imgFile: File | null; name: string }[];
|
||||||
|
}>({ selectedImage: '', list: [] });
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const flowStore = useFlowStore();
|
const flowStore = useFlowStore();
|
||||||
|
|
@ -30,11 +34,13 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
||||||
|
|
||||||
const registerAbleBranchOption = ref<{ id: string; name: string }[]>();
|
const registerAbleBranchOption = ref<{ id: string; name: string }[]>();
|
||||||
|
|
||||||
|
const currentBranchRootId = ref<string>('');
|
||||||
|
|
||||||
const tabFieldRequired = ref<{
|
const tabFieldRequired = ref<{
|
||||||
[key: string]: (keyof CustomerBranchCreate)[];
|
[key: string]: (keyof CustomerBranchCreate)[];
|
||||||
}>({
|
}>({
|
||||||
main: [],
|
main: [],
|
||||||
business: ['businessType', 'jobPosition'],
|
business: ['businessTypeId', 'jobPosition'],
|
||||||
address: [
|
address: [
|
||||||
'address',
|
'address',
|
||||||
'addressEN',
|
'addressEN',
|
||||||
|
|
@ -82,6 +88,7 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
||||||
formDataOcr: Record<string, any>;
|
formDataOcr: Record<string, any>;
|
||||||
isImageEdit: boolean;
|
isImageEdit: boolean;
|
||||||
currentCustomerId?: string;
|
currentCustomerId?: string;
|
||||||
|
imageList: { list: string[]; selectedImage: string };
|
||||||
}>({
|
}>({
|
||||||
dialogType: 'info',
|
dialogType: 'info',
|
||||||
dialogOpen: false,
|
dialogOpen: false,
|
||||||
|
|
@ -98,6 +105,7 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
||||||
treeFile: [],
|
treeFile: [],
|
||||||
formDataOcr: {},
|
formDataOcr: {},
|
||||||
isImageEdit: false,
|
isImageEdit: false,
|
||||||
|
imageList: { list: [], selectedImage: '' },
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|
@ -160,6 +168,7 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
||||||
state.value.editCustomerCode = data.code;
|
state.value.editCustomerCode = data.code;
|
||||||
state.value.customerImageUrl = `${baseUrl}/customer/${id}/image/${data.selectedImage}`;
|
state.value.customerImageUrl = `${baseUrl}/customer/${id}/image/${data.selectedImage}`;
|
||||||
state.value.defaultCustomerImageUrl = `${baseUrl}/customer/${id}/image/${data.selectedImage}`;
|
state.value.defaultCustomerImageUrl = `${baseUrl}/customer/${id}/image/${data.selectedImage}`;
|
||||||
|
currentBranchRootId.value = data.branch[0].id || '';
|
||||||
|
|
||||||
resetFormData.registeredBranchId = data.registeredBranchId;
|
resetFormData.registeredBranchId = data.registeredBranchId;
|
||||||
resetFormData.status = data.status;
|
resetFormData.status = data.status;
|
||||||
|
|
@ -181,7 +190,7 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
||||||
payDate: v.payDate,
|
payDate: v.payDate,
|
||||||
jobDescription: v.jobDescription,
|
jobDescription: v.jobDescription,
|
||||||
jobPosition: v.jobPosition,
|
jobPosition: v.jobPosition,
|
||||||
businessType: v.businessType,
|
businessTypeId: v.businessTypeId,
|
||||||
employmentOffice: v.employmentOffice,
|
employmentOffice: v.employmentOffice,
|
||||||
employmentOfficeEN: v.employmentOfficeEN,
|
employmentOfficeEN: v.employmentOfficeEN,
|
||||||
telephoneNo: v.telephoneNo,
|
telephoneNo: v.telephoneNo,
|
||||||
|
|
@ -218,7 +227,6 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
||||||
contactTel: v.contactTel,
|
contactTel: v.contactTel,
|
||||||
officeTel: v.officeTel,
|
officeTel: v.officeTel,
|
||||||
agentUserId: v.agentUserId || undefined,
|
agentUserId: v.agentUserId || undefined,
|
||||||
customerName: v.customerName,
|
|
||||||
authorizedName: v.authorizedName,
|
authorizedName: v.authorizedName,
|
||||||
authorizedNameEN: v.authorizedNameEN,
|
authorizedNameEN: v.authorizedNameEN,
|
||||||
|
|
||||||
|
|
@ -256,7 +264,6 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
||||||
async function addCurrentCustomerBranch() {
|
async function addCurrentCustomerBranch() {
|
||||||
if (currentFormData.value.customerBranch?.some((v) => !v.id)) return;
|
if (currentFormData.value.customerBranch?.some((v) => !v.id)) return;
|
||||||
currentFormData.value.customerBranch?.push({
|
currentFormData.value.customerBranch?.push({
|
||||||
id: '',
|
|
||||||
customerId: '',
|
customerId: '',
|
||||||
branchCode:
|
branchCode:
|
||||||
currentFormData.value.customerBranch.length !== 0
|
currentFormData.value.customerBranch.length !== 0
|
||||||
|
|
@ -290,8 +297,8 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
||||||
birthDate:
|
birthDate:
|
||||||
currentFormData.value.customerBranch?.at(0)?.birthDate || undefined,
|
currentFormData.value.customerBranch?.at(0)?.birthDate || undefined,
|
||||||
|
|
||||||
businessType:
|
businessTypeId:
|
||||||
currentFormData.value.customerBranch?.at(0)?.businessType || '',
|
currentFormData.value.customerBranch?.at(0)?.businessTypeId || '',
|
||||||
jobPosition:
|
jobPosition:
|
||||||
currentFormData.value.customerBranch?.at(0)?.jobPosition || '',
|
currentFormData.value.customerBranch?.at(0)?.jobPosition || '',
|
||||||
jobDescription:
|
jobDescription:
|
||||||
|
|
@ -328,8 +335,6 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
||||||
currentFormData.value.customerBranch?.at(0)?.agentUserId || undefined,
|
currentFormData.value.customerBranch?.at(0)?.agentUserId || undefined,
|
||||||
status: 'CREATED',
|
status: 'CREATED',
|
||||||
|
|
||||||
customerName:
|
|
||||||
currentFormData.value.customerBranch?.at(0)?.customerName || '',
|
|
||||||
registerName:
|
registerName:
|
||||||
currentFormData.value.customerBranch?.at(0)?.registerName || '',
|
currentFormData.value.customerBranch?.at(0)?.registerName || '',
|
||||||
registerNameEN:
|
registerNameEN:
|
||||||
|
|
@ -498,11 +503,14 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
onCreateImageList,
|
||||||
tabFieldRequired,
|
tabFieldRequired,
|
||||||
registerAbleBranchOption,
|
registerAbleBranchOption,
|
||||||
state,
|
state,
|
||||||
resetFormData,
|
resetFormData,
|
||||||
currentFormData,
|
currentFormData,
|
||||||
|
currentBranchRootId,
|
||||||
|
|
||||||
isFormDataDifferent,
|
isFormDataDifferent,
|
||||||
resetForm,
|
resetForm,
|
||||||
assignFormData,
|
assignFormData,
|
||||||
|
|
@ -541,7 +549,7 @@ export const useCustomerBranchForm = defineStore('form-customer-branch', () => {
|
||||||
gender: '',
|
gender: '',
|
||||||
birthDate: undefined,
|
birthDate: undefined,
|
||||||
|
|
||||||
businessType: '',
|
businessTypeId: '',
|
||||||
jobPosition: '',
|
jobPosition: '',
|
||||||
jobDescription: '',
|
jobDescription: '',
|
||||||
payDate: '',
|
payDate: '',
|
||||||
|
|
@ -571,7 +579,6 @@ export const useCustomerBranchForm = defineStore('form-customer-branch', () => {
|
||||||
agentUserId: undefined,
|
agentUserId: undefined,
|
||||||
status: 'CREATED',
|
status: 'CREATED',
|
||||||
|
|
||||||
customerName: '',
|
|
||||||
registerName: '',
|
registerName: '',
|
||||||
registerNameEN: '',
|
registerNameEN: '',
|
||||||
registerDate: undefined,
|
registerDate: undefined,
|
||||||
|
|
@ -623,7 +630,7 @@ export const useCustomerBranchForm = defineStore('form-customer-branch', () => {
|
||||||
payDateEN: _data.payDateEN,
|
payDateEN: _data.payDateEN,
|
||||||
jobDescription: _data.jobDescription,
|
jobDescription: _data.jobDescription,
|
||||||
jobPosition: _data.jobPosition,
|
jobPosition: _data.jobPosition,
|
||||||
businessType: _data.businessType,
|
businessTypeId: _data.businessTypeId,
|
||||||
employmentOffice: _data.employmentOffice,
|
employmentOffice: _data.employmentOffice,
|
||||||
employmentOfficeEN: _data.employmentOfficeEN,
|
employmentOfficeEN: _data.employmentOfficeEN,
|
||||||
telephoneNo: _data.telephoneNo,
|
telephoneNo: _data.telephoneNo,
|
||||||
|
|
@ -657,7 +664,6 @@ export const useCustomerBranchForm = defineStore('form-customer-branch', () => {
|
||||||
officeTel: _data.officeTel,
|
officeTel: _data.officeTel,
|
||||||
agentUserId: _data.agentUserId || undefined,
|
agentUserId: _data.agentUserId || undefined,
|
||||||
codeCustomer: _data.codeCustomer,
|
codeCustomer: _data.codeCustomer,
|
||||||
customerName: _data.customerName,
|
|
||||||
homeCode: _data.homeCode,
|
homeCode: _data.homeCode,
|
||||||
authorizedName: _data.authorizedName,
|
authorizedName: _data.authorizedName,
|
||||||
authorizedNameEN: _data.authorizedNameEN,
|
authorizedNameEN: _data.authorizedNameEN,
|
||||||
|
|
@ -784,6 +790,7 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
||||||
}
|
}
|
||||||
| undefined;
|
| undefined;
|
||||||
ocr: boolean;
|
ocr: boolean;
|
||||||
|
imageList: { list: string[]; selectedImage: string };
|
||||||
}>({
|
}>({
|
||||||
currentBranchId: '',
|
currentBranchId: '',
|
||||||
isImageEdit: false,
|
isImageEdit: false,
|
||||||
|
|
@ -808,9 +815,10 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
||||||
infoEmployeePersonCard: [],
|
infoEmployeePersonCard: [],
|
||||||
formDataEmployeeOwner: undefined,
|
formDataEmployeeOwner: undefined,
|
||||||
ocr: false,
|
ocr: false,
|
||||||
|
imageList: { list: [], selectedImage: '' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultFormData: EmployeeCreate = {
|
const defaultFormData: EmployeeCreate & { image?: File } = {
|
||||||
id: '',
|
id: '',
|
||||||
code: '',
|
code: '',
|
||||||
customerBranchId: '',
|
customerBranchId: '',
|
||||||
|
|
@ -892,6 +900,7 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
||||||
expireDate: new Date(),
|
expireDate: new Date(),
|
||||||
remark: undefined,
|
remark: undefined,
|
||||||
workerType: '',
|
workerType: '',
|
||||||
|
reportDate: null,
|
||||||
number: '',
|
number: '',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -937,7 +946,7 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
let resetEmployeeData = structuredClone(defaultFormData);
|
let resetEmployeeData = structuredClone(defaultFormData);
|
||||||
const currentFromDataEmployee = ref<EmployeeCreate>(
|
const currentFromDataEmployee = ref<EmployeeCreate & { image?: File }>(
|
||||||
structuredClone(defaultFormData),
|
structuredClone(defaultFormData),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -959,6 +968,7 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
||||||
state.value.currentIndexVisa = -1;
|
state.value.currentIndexVisa = -1;
|
||||||
state.value.currentIndexCheckup = -1;
|
state.value.currentIndexCheckup = -1;
|
||||||
state.value.currentIndexWorkHistory = -1;
|
state.value.currentIndexWorkHistory = -1;
|
||||||
|
state.value.imageList = { list: [], selectedImage: '' };
|
||||||
// state.value.currentTab = 'personalInfo';
|
// state.value.currentTab = 'personalInfo';
|
||||||
if (clean) {
|
if (clean) {
|
||||||
state.value.formDataEmployeeOwner = undefined;
|
state.value.formDataEmployeeOwner = undefined;
|
||||||
|
|
@ -986,12 +996,16 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
||||||
state.value.currentIndexPassport
|
state.value.currentIndexPassport
|
||||||
].id === undefined
|
].id === undefined
|
||||||
) {
|
) {
|
||||||
|
const { id, employeeId, updatedAt, createdAt, file, ...payload } =
|
||||||
|
currentFromDataEmployee.value.employeePassport?.[
|
||||||
|
state.value.currentIndexPassport
|
||||||
|
];
|
||||||
|
|
||||||
const res = await employeeStore.postMeta({
|
const res = await employeeStore.postMeta({
|
||||||
parentId: currentFromDataEmployee.value.id || '',
|
parentId: currentFromDataEmployee.value.id || '',
|
||||||
group: 'passport',
|
group: 'passport',
|
||||||
meta: currentFromDataEmployee.value.employeePassport?.[
|
meta: payload,
|
||||||
state.value.currentIndexPassport
|
file: file,
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
|
|
@ -1005,7 +1019,7 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
||||||
state.value.currentIndexPassport
|
state.value.currentIndexPassport
|
||||||
].id !== undefined
|
].id !== undefined
|
||||||
) {
|
) {
|
||||||
const { id, employeeId, updatedAt, createdAt, ...payload } =
|
const { id, employeeId, updatedAt, createdAt, file, ...payload } =
|
||||||
currentFromDataEmployee.value.employeePassport?.[
|
currentFromDataEmployee.value.employeePassport?.[
|
||||||
state.value.currentIndexPassport
|
state.value.currentIndexPassport
|
||||||
];
|
];
|
||||||
|
|
@ -1018,6 +1032,7 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
||||||
state.value.currentIndexPassport
|
state.value.currentIndexPassport
|
||||||
].id || '',
|
].id || '',
|
||||||
meta: payload,
|
meta: payload,
|
||||||
|
file: file || undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1245,7 +1260,7 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
||||||
await assignFormDataEmployee(currentFromDataEmployee.value.id);
|
await assignFormDataEmployee(currentFromDataEmployee.value.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitPersonal(imgList: {
|
async function submitPersonal(imgList?: {
|
||||||
selectedImage: string;
|
selectedImage: string;
|
||||||
list: { url: string; imgFile: File | null; name: string }[];
|
list: { url: string; imgFile: File | null; name: string }[];
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -1266,6 +1281,7 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
||||||
currentFromDataEmployee.value.lastNameEN.trim();
|
currentFromDataEmployee.value.lastNameEN.trim();
|
||||||
|
|
||||||
if (state.value.dialogType === 'create') {
|
if (state.value.dialogType === 'create') {
|
||||||
|
delete currentFromDataEmployee.value.image;
|
||||||
const res = await employeeStore.create(
|
const res = await employeeStore.create(
|
||||||
{
|
{
|
||||||
...currentFromDataEmployee.value,
|
...currentFromDataEmployee.value,
|
||||||
|
|
@ -1382,12 +1398,10 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
||||||
statusSave: true,
|
statusSave: true,
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
employeeOtherInfo: structuredClone(
|
employeeOtherInfo: structuredClone({
|
||||||
{
|
...(payload.employeeOtherInfo ?? {}),
|
||||||
...payload.employeeOtherInfo,
|
statusSave: true,
|
||||||
statusSave: !!payload.employeeOtherInfo?.id ? true : false,
|
}),
|
||||||
} || {},
|
|
||||||
),
|
|
||||||
employeeWork: structuredClone(
|
employeeWork: structuredClone(
|
||||||
payload.employeeWork?.length === 0
|
payload.employeeWork?.length === 0
|
||||||
? state.value.dialogModal
|
? state.value.dialogModal
|
||||||
|
|
@ -1536,6 +1550,7 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
||||||
expireDate: new Date(),
|
expireDate: new Date(),
|
||||||
remark: undefined,
|
remark: undefined,
|
||||||
workerType: '',
|
workerType: '',
|
||||||
|
reportDate: null,
|
||||||
number: '',
|
number: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1660,6 +1675,7 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
||||||
state,
|
state,
|
||||||
currentFromDataEmployee,
|
currentFromDataEmployee,
|
||||||
resetEmployeeData,
|
resetEmployeeData,
|
||||||
|
|
||||||
addPassport,
|
addPassport,
|
||||||
addVisa,
|
addVisa,
|
||||||
addCheckup,
|
addCheckup,
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
isEdit?: boolean;
|
isEdit?: boolean;
|
||||||
|
hideAction?: boolean;
|
||||||
}>(),
|
}>(),
|
||||||
{ readonly: false, isEdit: false },
|
{ readonly: false, isEdit: false },
|
||||||
);
|
);
|
||||||
|
|
@ -207,7 +208,7 @@ function triggerPropertiesDialog(step: WorkFlowPayloadStep) {
|
||||||
style="position: absolute; z-index: 999; top: 0; right: 0"
|
style="position: absolute; z-index: 999; top: 0; right: 0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="flowData.status !== 'INACTIVE'"
|
v-if="flowData.status !== 'INACTIVE' && !hideAction"
|
||||||
class="surface-1 row rounded"
|
class="surface-1 row rounded"
|
||||||
>
|
>
|
||||||
<UndoButton
|
<UndoButton
|
||||||
|
|
@ -287,6 +288,7 @@ function triggerPropertiesDialog(step: WorkFlowPayloadStep) {
|
||||||
>
|
>
|
||||||
<template v-slot:btn-form-flow-step-drawer>
|
<template v-slot:btn-form-flow-step-drawer>
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="!hideAction"
|
||||||
dense
|
dense
|
||||||
flat
|
flat
|
||||||
icon="mdi-plus"
|
icon="mdi-plus"
|
||||||
|
|
@ -315,6 +317,7 @@ function triggerPropertiesDialog(step: WorkFlowPayloadStep) {
|
||||||
<FormFlow
|
<FormFlow
|
||||||
:readonly
|
:readonly
|
||||||
onDrawer
|
onDrawer
|
||||||
|
:hide-action="hideAction"
|
||||||
v-model:user-in-table="userInTable"
|
v-model:user-in-table="userInTable"
|
||||||
v-model:flow-data="flowData"
|
v-model:flow-data="flowData"
|
||||||
v-model:register-branch-id="registerBranchId"
|
v-model:register-branch-id="registerBranchId"
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import {
|
||||||
} from 'src/stores/workflow-template/types';
|
} from 'src/stores/workflow-template/types';
|
||||||
import { useWorkflowTemplate } from 'src/stores/workflow-template';
|
import { useWorkflowTemplate } from 'src/stores/workflow-template';
|
||||||
import { useNavigator } from 'src/stores/navigator';
|
import { useNavigator } from 'src/stores/navigator';
|
||||||
import { dialog } from 'src/stores/utils';
|
import { dialog, canAccess } from 'src/stores/utils';
|
||||||
|
|
||||||
import FloatingActionButton from 'components/FloatingActionButton.vue';
|
import FloatingActionButton from 'components/FloatingActionButton.vue';
|
||||||
import StatCardComponent from 'src/components/StatCardComponent.vue';
|
import StatCardComponent from 'src/components/StatCardComponent.vue';
|
||||||
|
|
@ -334,6 +334,7 @@ watch(
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FloatingActionButton
|
<FloatingActionButton
|
||||||
|
v-if="canAccess('workflow', 'edit')"
|
||||||
style="z-index: 999"
|
style="z-index: 999"
|
||||||
hide-icon
|
hide-icon
|
||||||
@click="triggerDialog('add')"
|
@click="triggerDialog('add')"
|
||||||
|
|
@ -682,6 +683,7 @@ watch(
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<KebabAction
|
<KebabAction
|
||||||
|
v-if="canAccess('workflow', 'edit')"
|
||||||
:id-name="props.row.name"
|
:id-name="props.row.name"
|
||||||
:status="props.row.status"
|
:status="props.row.status"
|
||||||
@view="
|
@view="
|
||||||
|
|
@ -763,6 +765,7 @@ watch(
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<KebabAction
|
<KebabAction
|
||||||
|
v-if="canAccess('workflow', 'edit')"
|
||||||
:id-name="props.row.name"
|
:id-name="props.row.name"
|
||||||
:status="props.row.status"
|
:status="props.row.status"
|
||||||
@view="
|
@view="
|
||||||
|
|
@ -846,6 +849,7 @@ watch(
|
||||||
@drawer-undo="undo"
|
@drawer-undo="undo"
|
||||||
@close="resetForm"
|
@close="resetForm"
|
||||||
@submit="submit"
|
@submit="submit"
|
||||||
|
:hide-action="!canAccess('workflow', 'edit')"
|
||||||
:readonly="!pageState.isDrawerEdit"
|
:readonly="!pageState.isDrawerEdit"
|
||||||
:isEdit="pageState.isDrawerEdit"
|
:isEdit="pageState.isDrawerEdit"
|
||||||
v-model="pageState.addModal"
|
v-model="pageState.addModal"
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ import PaginationPageSize from 'src/components/PaginationPageSize.vue';
|
||||||
import useFlowStore from 'stores/flow';
|
import useFlowStore from 'stores/flow';
|
||||||
|
|
||||||
import { dateFormat } from 'src/utils/datetime';
|
import { dateFormat } from 'src/utils/datetime';
|
||||||
import { formatNumberDecimal, isRoleInclude, notify } from 'stores/utils';
|
import { formatNumberDecimal, isRoleInclude, canAccess } from 'stores/utils';
|
||||||
const { getWorkflowTemplate } = useWorkflowTemplate();
|
const { getWorkflowTemplate } = useWorkflowTemplate();
|
||||||
|
|
||||||
import { Status } from 'stores/types';
|
import { Status } from 'stores/types';
|
||||||
|
|
@ -102,6 +102,8 @@ const {
|
||||||
deleteWork,
|
deleteWork,
|
||||||
|
|
||||||
importProduct,
|
importProduct,
|
||||||
|
|
||||||
|
productExport,
|
||||||
} = productServiceStore;
|
} = productServiceStore;
|
||||||
|
|
||||||
const { workNameItems } = storeToRefs(productServiceStore);
|
const { workNameItems } = storeToRefs(productServiceStore);
|
||||||
|
|
@ -143,27 +145,25 @@ const { t } = useI18n();
|
||||||
const baseUrl = ref<string>(import.meta.env.VITE_API_BASE_URL);
|
const baseUrl = ref<string>(import.meta.env.VITE_API_BASE_URL);
|
||||||
|
|
||||||
const priceDisplay = computed(() => ({
|
const priceDisplay = computed(() => ({
|
||||||
price: !isRoleInclude(['sale_agent']),
|
// price: !isRoleInclude(['sale_agent']),
|
||||||
|
price: true,
|
||||||
agentPrice: isRoleInclude([
|
agentPrice: isRoleInclude([
|
||||||
'admin',
|
|
||||||
'head_of_admin',
|
|
||||||
'head_of_sale',
|
|
||||||
'system',
|
'system',
|
||||||
'owner',
|
'head_of_admin',
|
||||||
|
'admin',
|
||||||
|
'executive',
|
||||||
'accountant',
|
'accountant',
|
||||||
'sale_agent',
|
'head_of_sale',
|
||||||
]),
|
]),
|
||||||
serviceCharge: isRoleInclude([
|
serviceCharge: isRoleInclude([
|
||||||
'admin',
|
|
||||||
'head_of_admin',
|
|
||||||
'system',
|
'system',
|
||||||
'owner',
|
'head_of_admin',
|
||||||
|
'admin',
|
||||||
|
'executive',
|
||||||
'accountant',
|
'accountant',
|
||||||
]),
|
]),
|
||||||
}));
|
}));
|
||||||
const actionDisplay = computed(() =>
|
const actionDisplay = computed(() => canAccess('product', 'edit'));
|
||||||
isRoleInclude(['admin', 'head_of_admin', 'system', 'owner', 'accountant']),
|
|
||||||
);
|
|
||||||
const splitterModel = computed(() =>
|
const splitterModel = computed(() =>
|
||||||
$q.screen.lt.md ? (productMode.value !== 'group' ? 0 : 100) : 25,
|
$q.screen.lt.md ? (productMode.value !== 'group' ? 0 : 100) : 25,
|
||||||
);
|
);
|
||||||
|
|
@ -1171,6 +1171,7 @@ function clearFormService() {
|
||||||
profileSubmit.value = false;
|
profileSubmit.value = false;
|
||||||
imageProduct.value = undefined;
|
imageProduct.value = undefined;
|
||||||
profileFileImg.value = null;
|
profileFileImg.value = null;
|
||||||
|
serviceTab.value = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sameFormService() {
|
function sameFormService() {
|
||||||
|
|
@ -1397,6 +1398,7 @@ function submitAddWorkProduct() {
|
||||||
if (!s.hasOwnProperty('productsId')) {
|
if (!s.hasOwnProperty('productsId')) {
|
||||||
s.productsId = [];
|
s.productsId = [];
|
||||||
}
|
}
|
||||||
|
if (s.productsId.length === 0) return;
|
||||||
s.productsId.push(i.id);
|
s.productsId.push(i.id);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -1897,6 +1899,25 @@ async function submitWorkName(
|
||||||
else await editWork(workId, data);
|
else await editWork(workId, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function triggerExport() {
|
||||||
|
productExport({
|
||||||
|
pageSize: 100_000,
|
||||||
|
productGroupId: currentIdGroup.value,
|
||||||
|
query: !!inputSearchProductAndService.value
|
||||||
|
? inputSearchProductAndService.value
|
||||||
|
: undefined,
|
||||||
|
status:
|
||||||
|
currentStatus.value === 'INACTIVE'
|
||||||
|
? 'INACTIVE'
|
||||||
|
: currentStatus.value === 'ACTIVE'
|
||||||
|
? 'ACTIVE'
|
||||||
|
: undefined,
|
||||||
|
|
||||||
|
startDate: searchDate.value[0] ? new Date(searchDate.value[0]) : undefined,
|
||||||
|
endDate: searchDate.value[1] ? new Date(searchDate.value[1]) : undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => formService.value.attributes.workflowId,
|
() => formService.value.attributes.workflowId,
|
||||||
async (a, b) => {
|
async (a, b) => {
|
||||||
|
|
@ -2230,7 +2251,6 @@ watch(
|
||||||
</AdvanceSearch>
|
</AdvanceSearch>
|
||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
||||||
<div class="row col-md-6" style="white-space: nowrap">
|
<div class="row col-md-6" style="white-space: nowrap">
|
||||||
<q-select
|
<q-select
|
||||||
v-show="$q.screen.gt.sm"
|
v-show="$q.screen.gt.sm"
|
||||||
|
|
@ -2465,7 +2485,10 @@ watch(
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ props.row.detail || '-' }}
|
{{
|
||||||
|
props.row.detail.replace(/<\/?[^>]+(>|$)/g, '') ||
|
||||||
|
'-'
|
||||||
|
}}
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
||||||
<q-td
|
<q-td
|
||||||
|
|
@ -2658,7 +2681,15 @@ watch(
|
||||||
{{ $t('general.recordPerPage') }}
|
{{ $t('general.recordPerPage') }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<PaginationPageSize v-model="pageSizeGroup" />
|
<PaginationPageSize
|
||||||
|
v-model="pageSizeGroup"
|
||||||
|
:fetch-data="
|
||||||
|
async () => {
|
||||||
|
await fetchListGroups();
|
||||||
|
flowStore.rotate();
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -2770,6 +2801,13 @@ watch(
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<SaveButton
|
||||||
|
icon-only
|
||||||
|
:icon="'material-symbols:download'"
|
||||||
|
color="var(--info-bg)"
|
||||||
|
@click.stop="triggerExport()"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row col-md-6" style="white-space: nowrap">
|
<div class="row col-md-6" style="white-space: nowrap">
|
||||||
|
|
@ -3417,7 +3455,15 @@ watch(
|
||||||
{{ $t('general.recordPerPage') }}
|
{{ $t('general.recordPerPage') }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<PaginationPageSize v-model="pageSizeServiceAndProduct" />
|
<PaginationPageSize
|
||||||
|
v-model="pageSizeServiceAndProduct"
|
||||||
|
:fetch-data="
|
||||||
|
async () => {
|
||||||
|
await alternativeFetch();
|
||||||
|
flowStore.rotate();
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -3549,7 +3595,7 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="col-12 col-md-10"
|
class="col-12 col-md-10"
|
||||||
id="customer-form-content"
|
id="group-create"
|
||||||
:class="{
|
:class="{
|
||||||
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
||||||
'q-py-md q-px-lg': !$q.screen.gt.sm,
|
'q-py-md q-px-lg': !$q.screen.gt.sm,
|
||||||
|
|
@ -4068,7 +4114,7 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="col-12 col-md-10"
|
class="col-12 col-md-10"
|
||||||
id="customer-form-content"
|
id="product-create"
|
||||||
:class="{
|
:class="{
|
||||||
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
||||||
'q-pa-sm': !$q.screen.gt.sm,
|
'q-pa-sm': !$q.screen.gt.sm,
|
||||||
|
|
@ -4294,7 +4340,7 @@ watch(
|
||||||
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
||||||
'q-pa-sm': !$q.screen.gt.sm,
|
'q-pa-sm': !$q.screen.gt.sm,
|
||||||
}"
|
}"
|
||||||
id="customer-form-content"
|
id="product-info"
|
||||||
style="height: 100%; max-height: 100%; overflow-y: auto"
|
style="height: 100%; max-height: 100%; overflow-y: auto"
|
||||||
>
|
>
|
||||||
<BasicInfoProduct
|
<BasicInfoProduct
|
||||||
|
|
@ -4339,6 +4385,7 @@ watch(
|
||||||
|
|
||||||
<!-- add service -->
|
<!-- add service -->
|
||||||
<DialogForm
|
<DialogForm
|
||||||
|
v-if="dialogService"
|
||||||
hide-footer
|
hide-footer
|
||||||
no-address
|
no-address
|
||||||
no-app-box
|
no-app-box
|
||||||
|
|
@ -4475,6 +4522,11 @@ watch(
|
||||||
sub: true,
|
sub: true,
|
||||||
}))
|
}))
|
||||||
"
|
"
|
||||||
|
:active="{
|
||||||
|
background: 'hsla(var(--blue-6-hsl) / .2)',
|
||||||
|
foreground: 'var(--blue-6)',
|
||||||
|
}"
|
||||||
|
scroll-element="#service-create"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
|
|
@ -4497,7 +4549,7 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="col-12 col-md-10"
|
class="col-12 col-md-10"
|
||||||
id="customer-form-content"
|
id="service-create"
|
||||||
:class="{
|
:class="{
|
||||||
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
||||||
'q-pa-sm': !$q.screen.gt.sm,
|
'q-pa-sm': !$q.screen.gt.sm,
|
||||||
|
|
@ -4696,9 +4748,10 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
</DialogForm>
|
</DialogForm>
|
||||||
|
|
||||||
<!-- edit service -->
|
<!-- edit service edit package-->
|
||||||
<!-- :edit="!(formDataProductService.status === 'INACTIVE')" -->
|
<!-- :edit="!(formDataProductService.status === 'INACTIVE')" -->
|
||||||
<DialogForm
|
<DialogForm
|
||||||
|
v-if="dialogServiceEdit"
|
||||||
hide-footer
|
hide-footer
|
||||||
no-address
|
no-address
|
||||||
height="95vh"
|
height="95vh"
|
||||||
|
|
@ -4951,6 +5004,7 @@ watch(
|
||||||
background: 'hsla(var(--blue-6-hsl) / .2)',
|
background: 'hsla(var(--blue-6-hsl) / .2)',
|
||||||
foreground: 'var(--blue-6)',
|
foreground: 'var(--blue-6)',
|
||||||
}"
|
}"
|
||||||
|
scroll-element="#service-info"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
|
|
@ -4973,7 +5027,7 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="col-12 col-md-10"
|
class="col-12 col-md-10"
|
||||||
id="customer-form-content"
|
id="service-info"
|
||||||
:class="{
|
:class="{
|
||||||
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
||||||
'q-pa-sm': !$q.screen.gt.sm,
|
'q-pa-sm': !$q.screen.gt.sm,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import { FloatingActionButton, PaginationComponent } from 'src/components';
|
||||||
import PaginationPageSize from 'src/components/PaginationPageSize.vue';
|
import PaginationPageSize from 'src/components/PaginationPageSize.vue';
|
||||||
import PropertyDialog from './PropertyDialog.vue';
|
import PropertyDialog from './PropertyDialog.vue';
|
||||||
import { Property } from 'src/stores/property/types';
|
import { Property } from 'src/stores/property/types';
|
||||||
import { dialog, toCamelCase } from 'src/stores/utils';
|
import { dialog, toCamelCase, canAccess } from 'src/stores/utils';
|
||||||
import CreateButton from 'src/components/AddButton.vue';
|
import CreateButton from 'src/components/AddButton.vue';
|
||||||
import useOptionStore from 'stores/options';
|
import useOptionStore from 'stores/options';
|
||||||
import AdvanceSearch from 'src/components/shared/AdvanceSearch.vue';
|
import AdvanceSearch from 'src/components/shared/AdvanceSearch.vue';
|
||||||
|
|
@ -331,6 +331,7 @@ watch(
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FloatingActionButton
|
<FloatingActionButton
|
||||||
|
v-if="canAccess('workflow', 'edit')"
|
||||||
style="z-index: 999"
|
style="z-index: 999"
|
||||||
hide-icon
|
hide-icon
|
||||||
@click="triggerDialog('add')"
|
@click="triggerDialog('add')"
|
||||||
|
|
@ -536,11 +537,19 @@ watch(
|
||||||
class="col surface-2 flex items-center justify-center"
|
class="col surface-2 flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<NoData
|
<NoData
|
||||||
v-if="pageState.total !== 0 || pageState.searchDate.length > 0"
|
v-if="
|
||||||
|
pageState.total !== 0 ||
|
||||||
|
pageState.searchDate.length > 0 ||
|
||||||
|
!canAccess('workflow', 'edit')
|
||||||
|
"
|
||||||
:not-found="!!pageState.inputSearch"
|
:not-found="!!pageState.inputSearch"
|
||||||
/>
|
/>
|
||||||
<CreateButton
|
<CreateButton
|
||||||
v-if="pageState.total === 0 && pageState.searchDate.length === 0"
|
v-if="
|
||||||
|
pageState.total === 0 &&
|
||||||
|
pageState.searchDate.length === 0 &&
|
||||||
|
canAccess('workflow', 'edit')
|
||||||
|
"
|
||||||
@click="triggerDialog('add')"
|
@click="triggerDialog('add')"
|
||||||
label="general.add"
|
label="general.add"
|
||||||
:i18n-args="{ text: $t('flow.title') }"
|
:i18n-args="{ text: $t('flow.title') }"
|
||||||
|
|
@ -698,6 +707,7 @@ watch(
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<KebabAction
|
<KebabAction
|
||||||
|
v-if="canAccess('workflow', 'edit')"
|
||||||
:id-name="props.row.name"
|
:id-name="props.row.name"
|
||||||
:status="props.row.status"
|
:status="props.row.status"
|
||||||
@view="
|
@view="
|
||||||
|
|
@ -815,6 +825,7 @@ watch(
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<KebabAction
|
<KebabAction
|
||||||
|
v-if="canAccess('workflow', 'edit')"
|
||||||
:id-name="props.row.id"
|
:id-name="props.row.id"
|
||||||
:status="props.row.status"
|
:status="props.row.status"
|
||||||
@view="
|
@view="
|
||||||
|
|
@ -906,6 +917,7 @@ watch(
|
||||||
@drawer-undo="() => undo()"
|
@drawer-undo="() => undo()"
|
||||||
@close="() => resetForm()"
|
@close="() => resetForm()"
|
||||||
@submit="() => submit()"
|
@submit="() => submit()"
|
||||||
|
:hide-action="!canAccess('workflow', 'edit')"
|
||||||
:readonly="!pageState.isDrawerEdit"
|
:readonly="!pageState.isDrawerEdit"
|
||||||
:isEdit="pageState.isDrawerEdit"
|
:isEdit="pageState.isDrawerEdit"
|
||||||
v-model="pageState.addModal"
|
v-model="pageState.addModal"
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
isEdit?: boolean;
|
isEdit?: boolean;
|
||||||
|
hideAction?: boolean;
|
||||||
}>(),
|
}>(),
|
||||||
{ readonly: false, isEdit: false },
|
{ readonly: false, isEdit: false },
|
||||||
);
|
);
|
||||||
|
|
@ -151,7 +152,7 @@ defineEmits<{
|
||||||
style="position: absolute; z-index: 999; top: 0; right: 0"
|
style="position: absolute; z-index: 999; top: 0; right: 0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="propertyData.status !== 'INACTIVE'"
|
v-if="propertyData.status !== 'INACTIVE' && !hideAction"
|
||||||
class="surface-1 row rounded"
|
class="surface-1 row rounded"
|
||||||
>
|
>
|
||||||
<UndoButton
|
<UndoButton
|
||||||
|
|
@ -236,6 +237,7 @@ defineEmits<{
|
||||||
<FormProperty
|
<FormProperty
|
||||||
onDrawer
|
onDrawer
|
||||||
:readonly="!isEdit"
|
:readonly="!isEdit"
|
||||||
|
:disable-toggle="hideAction"
|
||||||
v-model:name="formProperty.name"
|
v-model:name="formProperty.name"
|
||||||
v-model:name-en="formProperty.nameEN"
|
v-model:name-en="formProperty.nameEN"
|
||||||
v-model:type="formProperty.type"
|
v-model:type="formProperty.type"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, reactive, ref, watch, computed } from 'vue';
|
import { onMounted, onUnmounted, reactive, ref, watch, computed } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
@ -14,7 +14,8 @@ import useMyBranch from 'stores/my-branch';
|
||||||
import { useQuotationForm } from './form';
|
import { useQuotationForm } from './form';
|
||||||
import { hslaColors } from './constants';
|
import { hslaColors } from './constants';
|
||||||
import { pageTabs, columnQuotation } from './constants';
|
import { pageTabs, columnQuotation } from './constants';
|
||||||
import { toCamelCase } from 'stores/utils';
|
import { toCamelCase, canAccess } from 'stores/utils';
|
||||||
|
import { getUserId } from 'src/services/keycloak';
|
||||||
|
|
||||||
// NOTE Import Types
|
// NOTE Import Types
|
||||||
import { CustomerBranchCreate, CustomerType } from 'stores/customer/types';
|
import { CustomerBranchCreate, CustomerType } from 'stores/customer/types';
|
||||||
|
|
@ -59,7 +60,6 @@ const flowStore = useFlowStore();
|
||||||
const userBranch = useMyBranch();
|
const userBranch = useMyBranch();
|
||||||
const navigatorStore = useNavigator();
|
const navigatorStore = useNavigator();
|
||||||
const customerStore = useCustomerStore();
|
const customerStore = useCustomerStore();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
fetchListOfOptionBranch,
|
fetchListOfOptionBranch,
|
||||||
customerFormUndo,
|
customerFormUndo,
|
||||||
|
|
@ -75,6 +75,7 @@ const {
|
||||||
const {
|
const {
|
||||||
state: customerFormState,
|
state: customerFormState,
|
||||||
currentFormData: customerFormData,
|
currentFormData: customerFormData,
|
||||||
|
currentBranchRootId,
|
||||||
registerAbleBranchOption,
|
registerAbleBranchOption,
|
||||||
tabFieldRequired,
|
tabFieldRequired,
|
||||||
} = storeToRefs(customerFormStore);
|
} = storeToRefs(customerFormStore);
|
||||||
|
|
@ -88,6 +89,8 @@ const fieldSelectedOption = computed(() => {
|
||||||
value: v.name,
|
value: v.name,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const keyAddDialog = ref<number>(0);
|
||||||
const special = ref(false);
|
const special = ref(false);
|
||||||
const branchId = ref('');
|
const branchId = ref('');
|
||||||
const agentPrice = ref<boolean>(false);
|
const agentPrice = ref<boolean>(false);
|
||||||
|
|
@ -104,6 +107,7 @@ const pageState = reactive({
|
||||||
fieldSelected: [''],
|
fieldSelected: [''],
|
||||||
gridView: false,
|
gridView: false,
|
||||||
total: 0,
|
total: 0,
|
||||||
|
sellerId: '',
|
||||||
|
|
||||||
currentTab: 'Issued',
|
currentTab: 'Issued',
|
||||||
addModal: false,
|
addModal: false,
|
||||||
|
|
@ -271,6 +275,10 @@ const customerNameInfo = computed(() => {
|
||||||
return name || '-';
|
return name || '-';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function handleWindowFocus() {
|
||||||
|
fetchQuotationList();
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
pageState.gridView = $q.screen.lt.md ? true : false;
|
pageState.gridView = $q.screen.lt.md ? true : false;
|
||||||
navigatorStore.current.title = 'quotation.title';
|
navigatorStore.current.title = 'quotation.title';
|
||||||
|
|
@ -297,6 +305,7 @@ onMounted(async () => {
|
||||||
pageSize: quotationPageSize.value,
|
pageSize: quotationPageSize.value,
|
||||||
status: 'Issued',
|
status: 'Issued',
|
||||||
urgentFirst: true,
|
urgentFirst: true,
|
||||||
|
sellerId: pageState.sellerId || undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
@ -307,6 +316,12 @@ onMounted(async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
flowStore.rotate();
|
flowStore.rotate();
|
||||||
|
|
||||||
|
window.addEventListener('focus', handleWindowFocus);
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('focus', handleWindowFocus);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function fetchQuotationList(mobileFetch?: boolean) {
|
async function fetchQuotationList(mobileFetch?: boolean) {
|
||||||
|
|
@ -331,6 +346,7 @@ async function fetchQuotationList(mobileFetch?: boolean) {
|
||||||
urgentFirst: true,
|
urgentFirst: true,
|
||||||
startDate: pageState.searchDate[0],
|
startDate: pageState.searchDate[0],
|
||||||
endDate: pageState.searchDate[1],
|
endDate: pageState.searchDate[1],
|
||||||
|
sellerId: pageState.sellerId || undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
@ -406,6 +422,11 @@ async function storeDataLocal(id: string) {
|
||||||
|
|
||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function filterBySellerId() {
|
||||||
|
pageState.sellerId = pageState.sellerId ? '' : getUserId();
|
||||||
|
await fetchQuotationList();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -413,6 +434,7 @@ async function storeDataLocal(id: string) {
|
||||||
hide-icon
|
hide-icon
|
||||||
style="z-index: 999"
|
style="z-index: 999"
|
||||||
@click.stop="triggerAddQuotationDialog"
|
@click.stop="triggerAddQuotationDialog"
|
||||||
|
v-if="canAccess('quotation', 'create')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="column full-height no-wrap">
|
<div class="column full-height no-wrap">
|
||||||
|
|
@ -528,7 +550,18 @@ async function storeDataLocal(id: string) {
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<q-separator vertical inset class="q-mr-xs" />
|
<q-separator vertical inset class="q-mr-xs" />
|
||||||
<AdvanceSearch v-model="pageState.searchDate" />
|
<AdvanceSearch v-model="pageState.searchDate">
|
||||||
|
<template #prepend>
|
||||||
|
<div class="text-weight-medium q-mb-sm">
|
||||||
|
<q-checkbox
|
||||||
|
size="xs"
|
||||||
|
:model-value="!!pageState.sellerId"
|
||||||
|
@click="filterBySellerId"
|
||||||
|
/>
|
||||||
|
{{ $t('quotation.ownOnly') }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</AdvanceSearch>
|
||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
||||||
|
|
@ -647,12 +680,20 @@ async function storeDataLocal(id: string) {
|
||||||
class="col surface-2 flex items-center justify-center"
|
class="col surface-2 flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<NoData
|
<NoData
|
||||||
v-if="pageState.inputSearch || pageState.currentTab !== 'Issued'"
|
v-if="
|
||||||
|
pageState.inputSearch ||
|
||||||
|
!canAccess('quotation', 'create') ||
|
||||||
|
pageState.currentTab !== 'Issued'
|
||||||
|
"
|
||||||
:not-found="!!pageState.inputSearch"
|
:not-found="!!pageState.inputSearch"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<CreateButton
|
<CreateButton
|
||||||
v-if="!pageState.inputSearch && pageState.currentTab === 'Issued'"
|
v-if="
|
||||||
|
!pageState.inputSearch &&
|
||||||
|
pageState.currentTab === 'Issued' &&
|
||||||
|
canAccess('quotation', 'create')
|
||||||
|
"
|
||||||
@click="triggerAddQuotationDialog"
|
@click="triggerAddQuotationDialog"
|
||||||
label="general.add"
|
label="general.add"
|
||||||
:i18n-args="{ text: $t('quotation.title') }"
|
:i18n-args="{ text: $t('quotation.title') }"
|
||||||
|
|
@ -682,6 +723,8 @@ async function storeDataLocal(id: string) {
|
||||||
:visible-columns="pageState.fieldSelected"
|
:visible-columns="pageState.fieldSelected"
|
||||||
:grid="pageState.gridView"
|
:grid="pageState.gridView"
|
||||||
:hide-edit="pageState.currentTab !== 'Issued'"
|
:hide-edit="pageState.currentTab !== 'Issued'"
|
||||||
|
:hide-action="!canAccess('quotation', 'edit')"
|
||||||
|
:hide-delete="!canAccess('quotation', 'delete')"
|
||||||
:hide-btn-preview="pageState.currentTab === 'PaymentSuccess'"
|
:hide-btn-preview="pageState.currentTab === 'PaymentSuccess'"
|
||||||
@preview="(id: any) => storeDataLocal(id)"
|
@preview="(id: any) => storeDataLocal(id)"
|
||||||
@view="
|
@view="
|
||||||
|
|
@ -707,7 +750,8 @@ async function storeDataLocal(id: string) {
|
||||||
<div class="col-md-4 col-sm-6 col-12 column">
|
<div class="col-md-4 col-sm-6 col-12 column">
|
||||||
<QuotationCard
|
<QuotationCard
|
||||||
class="col"
|
class="col"
|
||||||
hide-kebab-delete
|
:hide-action="!canAccess('quotation', 'edit')"
|
||||||
|
:hide-kebab-delete="!canAccess('quotation', 'delete')"
|
||||||
:hide-kebab-edit="!(pageState.currentTab === 'Issued')"
|
:hide-kebab-edit="!(pageState.currentTab === 'Issued')"
|
||||||
:hide-preview="pageState.currentTab === 'PaymentSuccess'"
|
:hide-preview="pageState.currentTab === 'PaymentSuccess'"
|
||||||
:urgent="item.row.urgent"
|
:urgent="item.row.urgent"
|
||||||
|
|
@ -733,8 +777,13 @@ async function storeDataLocal(id: string) {
|
||||||
:worker-count="item.row._count.worker"
|
:worker-count="item.row._count.worker"
|
||||||
:worker-max="item.row.workerMax || item.row._count.worker"
|
:worker-max="item.row.workerMax || item.row._count.worker"
|
||||||
:customer-name="
|
:customer-name="
|
||||||
item.row.customerBranch.registerName ||
|
item.row.customerBranch.customer.customerType === 'CORP'
|
||||||
`${item.row.customerBranch.firstName || '-'} ${item.row.customerBranch.lastName || ''}`
|
? $i18n.locale === 'tha'
|
||||||
|
? item.row.customerBranch.registerName
|
||||||
|
: item.row.customerBranch.registerNameEN
|
||||||
|
: $i18n.locale === 'tha'
|
||||||
|
? `${item.row.customerBranch.firstName || '-'} ${item.row.customerBranch.lastName || ''}`
|
||||||
|
: `${item.row.customerBranch.firstNameEN || '-'} ${item.row.customerBranch.lastNameEN || ''}`
|
||||||
"
|
"
|
||||||
:reporter="
|
:reporter="
|
||||||
$i18n.locale === 'eng'
|
$i18n.locale === 'eng'
|
||||||
|
|
@ -833,6 +882,7 @@ async function storeDataLocal(id: string) {
|
||||||
<!-- NOTE: START - Quotation Form, Add Quotation -->
|
<!-- NOTE: START - Quotation Form, Add Quotation -->
|
||||||
|
|
||||||
<DialogForm
|
<DialogForm
|
||||||
|
:key="keyAddDialog"
|
||||||
:title="$t('general.add', { text: $t('quotation.title') })"
|
:title="$t('general.add', { text: $t('quotation.title') })"
|
||||||
v-model:modal="pageState.addModal"
|
v-model:modal="pageState.addModal"
|
||||||
:submit-label="$t('general.add', { text: $t('quotation.title') })"
|
:submit-label="$t('general.add', { text: $t('quotation.title') })"
|
||||||
|
|
@ -842,13 +892,14 @@ async function storeDataLocal(id: string) {
|
||||||
:submit="
|
:submit="
|
||||||
() => {
|
() => {
|
||||||
quotationFormState.mode = 'create';
|
quotationFormState.mode = 'create';
|
||||||
|
quotationFormData.customerBranchId = currentBranchRootId;
|
||||||
triggerQuotationDialog({ statusDialog: 'create' });
|
triggerQuotationDialog({ statusDialog: 'create' });
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
:close="
|
:close="
|
||||||
() => {
|
() => {
|
||||||
branchId = '';
|
branchId = '';
|
||||||
quotationFormData.customerBranchId = '';
|
currentBranchRootId = '';
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
:beforeClose="
|
:beforeClose="
|
||||||
|
|
@ -898,7 +949,7 @@ async function storeDataLocal(id: string) {
|
||||||
v-model:agent-price="agentPrice"
|
v-model:agent-price="agentPrice"
|
||||||
v-model:branch-id="branchId"
|
v-model:branch-id="branchId"
|
||||||
v-model:special="special"
|
v-model:special="special"
|
||||||
v-model:customer-branch-id="quotationFormData.customerBranchId"
|
v-model:customer-branch-id="currentBranchRootId"
|
||||||
@add-customer="triggerSelectTypeCustomerd()"
|
@add-customer="triggerSelectTypeCustomerd()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -967,6 +1018,7 @@ async function storeDataLocal(id: string) {
|
||||||
() => {
|
() => {
|
||||||
customerFormState.dialogModal = false;
|
customerFormState.dialogModal = false;
|
||||||
onCreateImageList = { selectedImage: '', list: [] };
|
onCreateImageList = { selectedImage: '', list: [] };
|
||||||
|
keyAddDialog++;
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
|
@ -1158,7 +1210,7 @@ async function storeDataLocal(id: string) {
|
||||||
customerFormData.customerBranch[0].legalPersonNo
|
customerFormData.customerBranch[0].legalPersonNo
|
||||||
"
|
"
|
||||||
v-model:business-type="
|
v-model:business-type="
|
||||||
customerFormData.customerBranch[0].businessType
|
customerFormData.customerBranch[0].businessTypeId
|
||||||
"
|
"
|
||||||
v-model:job-position="
|
v-model:job-position="
|
||||||
customerFormData.customerBranch[0].jobPosition
|
customerFormData.customerBranch[0].jobPosition
|
||||||
|
|
@ -1239,7 +1291,6 @@ async function storeDataLocal(id: string) {
|
||||||
res = await customerStore.createBranch({
|
res = await customerStore.createBranch({
|
||||||
...customerFormData.customerBranch[idx],
|
...customerFormData.customerBranch[idx],
|
||||||
customerId: customerFormState.editCustomerId || '',
|
customerId: customerFormState.editCustomerId || '',
|
||||||
id: undefined,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (res) {
|
if (res) {
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,15 @@
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { QSelect, useQuasar } from 'quasar';
|
import { QSelect, useQuasar } from 'quasar';
|
||||||
|
import { getUserId } from 'src/services/keycloak';
|
||||||
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue';
|
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue';
|
||||||
import {
|
import {
|
||||||
baseUrl,
|
baseUrl,
|
||||||
dialogCheckData,
|
dialogCheckData,
|
||||||
dialogWarningClose,
|
dialogWarningClose,
|
||||||
formatNumberDecimal,
|
formatNumberDecimal,
|
||||||
|
canAccess,
|
||||||
|
isRoleInclude,
|
||||||
} from 'stores/utils';
|
} from 'stores/utils';
|
||||||
import { ProductTree, quotationProductTree } from './utils';
|
import { ProductTree, quotationProductTree } from './utils';
|
||||||
|
|
||||||
|
|
@ -76,7 +79,8 @@ import { api } from 'src/boot/axios';
|
||||||
import { RouterLink, useRoute } from 'vue-router';
|
import { RouterLink, useRoute } from 'vue-router';
|
||||||
import { initLang, initTheme, Lang } from 'src/utils/ui';
|
import { initLang, initTheme, Lang } from 'src/utils/ui';
|
||||||
import { convertTemplate } from 'src/utils/string-template';
|
import { convertTemplate } from 'src/utils/string-template';
|
||||||
import { getRole } from 'src/services/keycloak';
|
|
||||||
|
import { CustomerBranch } from 'src/stores/customer';
|
||||||
|
|
||||||
type Node = {
|
type Node = {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
|
|
@ -92,6 +96,8 @@ type ProductGroupId = string;
|
||||||
|
|
||||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
||||||
|
|
||||||
|
const customerBranchOption = ref<CustomerBranch>();
|
||||||
|
|
||||||
const employeeStore = useEmployeeStore();
|
const employeeStore = useEmployeeStore();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const useReceiptStore = useReceipt();
|
const useReceiptStore = useReceipt();
|
||||||
|
|
@ -155,49 +161,7 @@ const selectedWorker = ref<
|
||||||
}[];
|
}[];
|
||||||
})[]
|
})[]
|
||||||
>([]);
|
>([]);
|
||||||
const selectedWorkerItem = computed(() => {
|
const selectedWorkerItem = ref([]);
|
||||||
return [
|
|
||||||
...selectedWorker.value.map((e) => ({
|
|
||||||
foreignRefNo: e.employeePassport
|
|
||||||
? e.employeePassport[0]?.number || '-'
|
|
||||||
: '-',
|
|
||||||
employeeName:
|
|
||||||
locale.value === Lang.English
|
|
||||||
? `${e.firstNameEN} ${e.lastNameEN}`
|
|
||||||
: e.firstName
|
|
||||||
? `${e.firstName} ${e.lastName}`
|
|
||||||
: `${e.firstNameEN} ${e.lastNameEN}`,
|
|
||||||
birthDate: dateFormatJS({ date: e.dateOfBirth }),
|
|
||||||
gender: e.gender,
|
|
||||||
age: calculateAge(e.dateOfBirth),
|
|
||||||
nationality: optionStore.mapOption(e.nationality),
|
|
||||||
documentExpireDate:
|
|
||||||
e.employeePassport !== undefined &&
|
|
||||||
e.employeePassport[0]?.expireDate !== undefined
|
|
||||||
? dateFormatJS({ date: e.employeePassport[0]?.expireDate })
|
|
||||||
: '-',
|
|
||||||
imgUrl: e.selectedImage
|
|
||||||
? `${API_BASE_URL}/employee/${e.id}/image/${e.selectedImage}`
|
|
||||||
: '',
|
|
||||||
status: e.status,
|
|
||||||
})),
|
|
||||||
|
|
||||||
...newWorkerList.value.map((v: any) => ({
|
|
||||||
foreignRefNo: v.passportNo,
|
|
||||||
employeeName:
|
|
||||||
locale.value === Lang.English
|
|
||||||
? `${v.firstNameEN} ${v.lastNameEN}`
|
|
||||||
: `${v.firstName} ${v.lastName}`,
|
|
||||||
birthDate: dateFormatJS({ date: v.dateOfBirth }),
|
|
||||||
gender: v.gender,
|
|
||||||
age: calculateAge(v.dateOfBirth),
|
|
||||||
nationality: optionStore.mapOption(v.nationality),
|
|
||||||
documentExpireDate: '-',
|
|
||||||
imgUrl: '',
|
|
||||||
status: 'CREATED',
|
|
||||||
})),
|
|
||||||
];
|
|
||||||
});
|
|
||||||
const firstCodePayment = ref('');
|
const firstCodePayment = ref('');
|
||||||
const selectedProductGroup = ref('');
|
const selectedProductGroup = ref('');
|
||||||
const selectedInstallmentNo = ref<number[]>([]);
|
const selectedInstallmentNo = ref<number[]>([]);
|
||||||
|
|
@ -213,17 +177,6 @@ const attachmentData = ref<
|
||||||
url?: string;
|
url?: string;
|
||||||
}[]
|
}[]
|
||||||
>([]);
|
>([]);
|
||||||
const hideBtnApproveInvoice = computed(() => {
|
|
||||||
const role = getRole();
|
|
||||||
const allowedRoles = [
|
|
||||||
'system',
|
|
||||||
'head_of_admin',
|
|
||||||
'admin',
|
|
||||||
'head_of_accountant',
|
|
||||||
'accountant',
|
|
||||||
];
|
|
||||||
return !role || !role.some((r) => allowedRoles.includes(r));
|
|
||||||
});
|
|
||||||
|
|
||||||
const getToolbarConfig = computed(() => {
|
const getToolbarConfig = computed(() => {
|
||||||
const toolbar = [['left', 'center', 'justify'], ['toggle'], ['clip']];
|
const toolbar = [['left', 'center', 'justify'], ['toggle'], ['clip']];
|
||||||
|
|
@ -243,7 +196,7 @@ function getPrice(
|
||||||
) {
|
) {
|
||||||
if (filterHook) list = list.filter(filterHook);
|
if (filterHook) list = list.filter(filterHook);
|
||||||
|
|
||||||
return list.reduce(
|
const value = list.reduce(
|
||||||
(a, c) => {
|
(a, c) => {
|
||||||
if (
|
if (
|
||||||
selectedInstallmentNo.value.length > 0 &&
|
selectedInstallmentNo.value.length > 0 &&
|
||||||
|
|
@ -253,32 +206,25 @@ function getPrice(
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
const originalPrice = c.pricePerUnit;
|
|
||||||
const finalPriceWithVat = precisionRound(
|
|
||||||
originalPrice * (1 + (config.value?.vat || 0.07)),
|
|
||||||
);
|
|
||||||
const finalPriceNoVat =
|
|
||||||
finalPriceWithVat / (1 + (config.value?.vat || 0.07));
|
|
||||||
|
|
||||||
const price = finalPriceNoVat * c.amount;
|
|
||||||
const vat =
|
|
||||||
(finalPriceNoVat * c.amount - c.discount) * (config.value?.vat || 0.07);
|
|
||||||
|
|
||||||
const calcVat =
|
const calcVat =
|
||||||
c.product[agentPrice.value ? 'agentPriceCalcVat' : 'calcVat'];
|
c.product[agentPrice.value ? 'agentPriceCalcVat' : 'calcVat'];
|
||||||
|
const vatFactor = calcVat ? (config.value?.vat ?? 0.07) : 0;
|
||||||
|
|
||||||
a.totalPrice = precisionRound(a.totalPrice + price);
|
const pricePerUnit =
|
||||||
a.totalDiscount = precisionRound(a.totalDiscount + Number(c.discount));
|
precisionRound(c.pricePerUnit * (1 + vatFactor)) / (1 + vatFactor);
|
||||||
a.vat = calcVat ? precisionRound(a.vat + vat) : a.vat;
|
|
||||||
|
const price =
|
||||||
|
(pricePerUnit * c.amount * (1 + vatFactor) - c.discount) /
|
||||||
|
(1 + vatFactor);
|
||||||
|
const vat = price * vatFactor;
|
||||||
|
|
||||||
|
a.totalPrice = precisionRound(a.totalPrice + price + c.discount);
|
||||||
|
a.totalDiscount = precisionRound(a.totalDiscount + c.discount);
|
||||||
|
a.vat = precisionRound(a.vat + vat);
|
||||||
a.vatExcluded = calcVat
|
a.vatExcluded = calcVat
|
||||||
? a.vatExcluded
|
? a.vatExcluded
|
||||||
: precisionRound(a.vatExcluded + price);
|
: precisionRound(a.vatExcluded + price);
|
||||||
a.finalPrice = precisionRound(
|
a.finalPrice = precisionRound(a.totalPrice - a.totalDiscount + a.vat);
|
||||||
a.totalPrice -
|
|
||||||
a.totalDiscount +
|
|
||||||
a.vat -
|
|
||||||
Number(quotationFormData.value.discount || 0),
|
|
||||||
);
|
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
},
|
},
|
||||||
|
|
@ -290,6 +236,8 @@ function getPrice(
|
||||||
finalPrice: 0,
|
finalPrice: 0,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const summaryPrice = computed(() => getPrice(productServiceList.value));
|
const summaryPrice = computed(() => getPrice(productServiceList.value));
|
||||||
|
|
@ -568,7 +516,7 @@ async function convertDataToFormSubmit() {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
selectedWorker.value.forEach((v, i) => {
|
selectedWorkerItem.value.forEach((v, i) => {
|
||||||
if (v.attachment !== undefined) {
|
if (v.attachment !== undefined) {
|
||||||
v.attachment.forEach((value) => {
|
v.attachment.forEach((value) => {
|
||||||
fileItemNewWorker.value.push({
|
fileItemNewWorker.value.push({
|
||||||
|
|
@ -585,7 +533,7 @@ async function convertDataToFormSubmit() {
|
||||||
|
|
||||||
quotationFormData.value.worker = JSON.parse(
|
quotationFormData.value.worker = JSON.parse(
|
||||||
JSON.stringify([
|
JSON.stringify([
|
||||||
...selectedWorker.value.map((v) => {
|
...selectedWorkerItem.value.map((v) => {
|
||||||
{
|
{
|
||||||
return v.id;
|
return v.id;
|
||||||
}
|
}
|
||||||
|
|
@ -625,6 +573,7 @@ async function convertDataToFormSubmit() {
|
||||||
discount: quotationFormData.value.discount,
|
discount: quotationFormData.value.discount,
|
||||||
remark: quotationFormData.value.remark || '',
|
remark: quotationFormData.value.remark || '',
|
||||||
agentPrice: agentPrice.value,
|
agentPrice: agentPrice.value,
|
||||||
|
sellerId: quotationFormData.value.sellerId,
|
||||||
};
|
};
|
||||||
|
|
||||||
newWorkerList.value = [];
|
newWorkerList.value = [];
|
||||||
|
|
@ -727,19 +676,13 @@ function handleUpdateProductTable(
|
||||||
// handleChangePayType(quotationFormData.value.payCondition);
|
// handleChangePayType(quotationFormData.value.payCondition);
|
||||||
// calc price
|
// calc price
|
||||||
const calc = (c: QuotationPayload['productServiceList'][number]) => {
|
const calc = (c: QuotationPayload['productServiceList'][number]) => {
|
||||||
const originalPrice = c.pricePerUnit || 0;
|
const calcVat =
|
||||||
const finalPriceWithVat = precisionRound(
|
c.product[agentPrice.value ? 'agentPriceCalcVat' : 'calcVat'];
|
||||||
originalPrice * (1 + (config.value?.vat || 0.07)),
|
const vatFactor = calcVat ? (config.value?.vat ?? 0.07) : 0;
|
||||||
);
|
const pricePerUnit =
|
||||||
const finalPriceNoVat =
|
precisionRound(c.pricePerUnit * (1 + vatFactor)) / (1 + vatFactor);
|
||||||
finalPriceWithVat / (1 + (config.value?.vat || 0.07));
|
const price = pricePerUnit * c.amount * (1 + vatFactor) - c.discount;
|
||||||
|
return precisionRound(price);
|
||||||
const price = finalPriceNoVat * c.amount;
|
|
||||||
const vat = c.product.calcVat
|
|
||||||
? (finalPriceNoVat * c.amount - (c.discount || 0)) *
|
|
||||||
(config.value?.vat || 0.07)
|
|
||||||
: 0;
|
|
||||||
return precisionRound(price + vat);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// installment
|
// installment
|
||||||
|
|
@ -792,21 +735,16 @@ function toggleDeleteProduct(index: number) {
|
||||||
|
|
||||||
// cal curr amount
|
// cal curr amount
|
||||||
if (currPaySplit && currTempPaySplit) {
|
if (currPaySplit && currTempPaySplit) {
|
||||||
const price = agentPrice.value
|
const calcVat =
|
||||||
? currProduct.product.agentPrice
|
currProduct.product[agentPrice.value ? 'agentPriceCalcVat' : 'calcVat'];
|
||||||
: currProduct.product.price;
|
const vatFactor = calcVat ? (config.value?.vat ?? 0.07) : 0;
|
||||||
const pricePerUnit = currProduct.product.vatIncluded
|
|
||||||
? price / (1 + (config.value?.vat || 0.07))
|
|
||||||
: price;
|
|
||||||
const vat =
|
|
||||||
(pricePerUnit * currProduct.amount - currProduct.discount) *
|
|
||||||
(config.value?.vat || 0.07);
|
|
||||||
const finalPrice =
|
|
||||||
pricePerUnit * currProduct.amount +
|
|
||||||
vat -
|
|
||||||
Number(currProduct.discount || 0);
|
|
||||||
|
|
||||||
currTempPaySplit.amount = currPaySplit.amount - finalPrice;
|
const price = precisionRound(
|
||||||
|
currProduct.pricePerUnit * currProduct.amount * (1 + vatFactor) -
|
||||||
|
currProduct.discount,
|
||||||
|
);
|
||||||
|
|
||||||
|
currTempPaySplit.amount = currPaySplit.amount - price;
|
||||||
currPaySplit.amount = currTempPaySplit.amount;
|
currPaySplit.amount = currTempPaySplit.amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -828,7 +766,40 @@ function toggleDeleteProduct(index: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function assignWorkerToSelectedWorker() {
|
async function assignWorkerToSelectedWorker() {
|
||||||
selectedWorker.value = quotationFormData.value.worker;
|
selectedWorkerItem.value = quotationFormData.value.worker.map((e) => {
|
||||||
|
return {
|
||||||
|
id: e.id,
|
||||||
|
foreignRefNo: e.employeePassport
|
||||||
|
? e.employeePassport[0]?.number || '-'
|
||||||
|
: '-',
|
||||||
|
employeeName:
|
||||||
|
locale.value === Lang.English
|
||||||
|
? `${e.firstNameEN} ${e.lastNameEN}`
|
||||||
|
: `${e.firstName || e.firstNameEN} ${e.lastName || e.lastNameEN}`,
|
||||||
|
birthDate: dateFormatJS({ date: e.dateOfBirth }),
|
||||||
|
gender: e.gender,
|
||||||
|
age: calculateAge(e.dateOfBirth),
|
||||||
|
nationality: optionStore.mapOption(e.nationality),
|
||||||
|
documentExpireDate:
|
||||||
|
e.employeePassport !== undefined &&
|
||||||
|
e.employeePassport[0]?.expireDate !== undefined
|
||||||
|
? dateFormatJS({ date: e.employeePassport[0]?.expireDate })
|
||||||
|
: '-',
|
||||||
|
imgUrl: e.selectedImage
|
||||||
|
? `${API_BASE_URL}/employee/${e.id}/image/${e.selectedImage}`
|
||||||
|
: '',
|
||||||
|
employeePassport: e.employeePassport,
|
||||||
|
status: e.status,
|
||||||
|
workerNew: false,
|
||||||
|
lastNameEN: e.lastNameEN,
|
||||||
|
lastName: e.lastName,
|
||||||
|
middleNameEN: e.middleNameEN,
|
||||||
|
middleName: e.middleName,
|
||||||
|
firstNameEN: e.firstNameEN,
|
||||||
|
firstName: e.firstName,
|
||||||
|
namePrefix: e.namePrefix,
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertToTable(nodes: Node[]) {
|
function convertToTable(nodes: Node[]) {
|
||||||
|
|
@ -861,8 +832,7 @@ function convertToTable(nodes: Node[]) {
|
||||||
tempTableProduct.value = JSON.parse(JSON.stringify(list));
|
tempTableProduct.value = JSON.parse(JSON.stringify(list));
|
||||||
|
|
||||||
if (nodes.length > 0) {
|
if (nodes.length > 0) {
|
||||||
quotationFormData.value.paySplit = Array.apply(
|
quotationFormData.value.paySplit = Array.from(
|
||||||
null,
|
|
||||||
new Array(quotationFormData.value.paySplitCount),
|
new Array(quotationFormData.value.paySplitCount),
|
||||||
).map((_, i) => ({
|
).map((_, i) => ({
|
||||||
no: i + 1,
|
no: i + 1,
|
||||||
|
|
@ -888,21 +858,21 @@ function convertToTable(nodes: Node[]) {
|
||||||
|
|
||||||
function convertEmployeeToTable(selected: Employee[]) {
|
function convertEmployeeToTable(selected: Employee[]) {
|
||||||
productServiceList.value.forEach((v) => {
|
productServiceList.value.forEach((v) => {
|
||||||
if (selectedWorker.value.length === 0 && v.amount === 1) v.amount -= 1;
|
if (selectedWorkerItem.value.length === 0 && v.amount === 1) v.amount -= 1;
|
||||||
|
|
||||||
v.amount = Math.max(
|
v.amount = Math.max(
|
||||||
v.amount + selected.length - selectedWorker.value.length,
|
v.amount + selected.length - selectedWorkerItem.value.length,
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
|
||||||
const oldWorkerId: string[] = [];
|
const oldWorkerId: string[] = [];
|
||||||
const newWorkerIndex: number[] = [];
|
const newWorkerIndex: number[] = [];
|
||||||
|
|
||||||
selectedWorker.value.forEach((item, i) => {
|
selectedWorkerItem.value.forEach((item, i) => {
|
||||||
if (v.workerIndex.includes(i)) oldWorkerId.push(item.id);
|
if (v.workerIndex.includes(i)) oldWorkerId.push(item.id);
|
||||||
});
|
});
|
||||||
selected.forEach((item, i) => {
|
selected.forEach((item, i) => {
|
||||||
if (selectedWorker.value.find((n) => item.id === n.id)) return;
|
if (selectedWorkerItem.value.find((n) => item.id === n.id)) return;
|
||||||
newWorkerIndex.push(i);
|
newWorkerIndex.push(i);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -915,7 +885,7 @@ function convertEmployeeToTable(selected: Employee[]) {
|
||||||
pageState.employeeModal = false;
|
pageState.employeeModal = false;
|
||||||
quotationFormData.value.workerMax = Math.max(
|
quotationFormData.value.workerMax = Math.max(
|
||||||
quotationFormData.value.workerMax || 1,
|
quotationFormData.value.workerMax || 1,
|
||||||
selectedWorker.value.length,
|
selectedWorkerItem.value.length,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -988,6 +958,71 @@ function viewProductFile(data: ProductRelation) {
|
||||||
pageState.imageDialogUrl = base64 ? base64[1] : '';
|
pageState.imageDialogUrl = base64 ? base64[1] : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function combineWorker(newWorker: any, oldWorker: any) {
|
||||||
|
selectedWorkerItem.value = [
|
||||||
|
...oldWorker.map((e) => ({
|
||||||
|
id: e.id,
|
||||||
|
foreignRefNo: e.employeePassport
|
||||||
|
? e.employeePassport[0]?.number || '-'
|
||||||
|
: '-',
|
||||||
|
employeeName:
|
||||||
|
locale.value === Lang.English
|
||||||
|
? `${e.firstNameEN} ${e.lastNameEN}`
|
||||||
|
: `${e.firstName || e.firstNameEN} ${e.lastName || e.lastNameEN}`,
|
||||||
|
birthDate: dateFormatJS({ date: e.dateOfBirth }),
|
||||||
|
gender: e.gender,
|
||||||
|
age: calculateAge(e.dateOfBirth),
|
||||||
|
nationality: optionStore.mapOption(e.nationality),
|
||||||
|
documentExpireDate:
|
||||||
|
e.employeePassport !== undefined &&
|
||||||
|
e.employeePassport[0]?.expireDate !== undefined
|
||||||
|
? dateFormatJS({ date: e.employeePassport[0]?.expireDate })
|
||||||
|
: '-',
|
||||||
|
imgUrl: e.selectedImage
|
||||||
|
? `${API_BASE_URL}/employee/${e.id}/image/${e.selectedImage}`
|
||||||
|
: '',
|
||||||
|
|
||||||
|
employeePassport: e.employeePassport,
|
||||||
|
status: e.status,
|
||||||
|
workerNew: false,
|
||||||
|
lastNameEN: e.lastNameEN,
|
||||||
|
lastName: e.lastName,
|
||||||
|
middleNameEN: e.middleNameEN,
|
||||||
|
middleName: e.middleName,
|
||||||
|
firstNameEN: e.firstNameEN,
|
||||||
|
firstName: e.firstName,
|
||||||
|
namePrefix: e.namePrefix,
|
||||||
|
})),
|
||||||
|
|
||||||
|
...newWorker.map((v: any) => ({
|
||||||
|
id: v.id,
|
||||||
|
foreignRefNo: v.passportNo || '-',
|
||||||
|
employeeName:
|
||||||
|
locale.value === Lang.English
|
||||||
|
? `${v.firstNameEN} ${v.lastNameEN}`
|
||||||
|
: `${v.firstName || v.firstNameEN} ${v.lastName || v.lastNameEN}`,
|
||||||
|
birthDate: dateFormatJS({ date: v.dateOfBirth }),
|
||||||
|
gender: v.gender,
|
||||||
|
age: calculateAge(v.dateOfBirth),
|
||||||
|
nationality: optionStore.mapOption(v.nationality),
|
||||||
|
documentExpireDate: '-',
|
||||||
|
imgUrl: '',
|
||||||
|
status: 'CREATED',
|
||||||
|
|
||||||
|
lastNameEN: v.lastNameEN,
|
||||||
|
lastName: v.lastName,
|
||||||
|
middleNameEN: v.middleNameEN,
|
||||||
|
middleName: v.middleName,
|
||||||
|
firstNameEN: v.firstNameEN,
|
||||||
|
firstName: v.firstName,
|
||||||
|
namePrefix: v.namePrefix,
|
||||||
|
|
||||||
|
dateOfBirth: v.dateOfBirth,
|
||||||
|
workerNew: true,
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
const sessionData = ref<Record<string, any>>();
|
const sessionData = ref<Record<string, any>>();
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
|
@ -1024,6 +1059,7 @@ onMounted(async () => {
|
||||||
quotationFormData.value.customerBranchId = parsed.customerBranchId;
|
quotationFormData.value.customerBranchId = parsed.customerBranchId;
|
||||||
currentQuotationId.value = parsed.quotationId;
|
currentQuotationId.value = parsed.quotationId;
|
||||||
agentPrice.value = parsed.agentPrice;
|
agentPrice.value = parsed.agentPrice;
|
||||||
|
quotationFormData.value.sellerId = getUserId();
|
||||||
await fetchQuotation();
|
await fetchQuotation();
|
||||||
await assignWorkerToSelectedWorker();
|
await assignWorkerToSelectedWorker();
|
||||||
sessionData.value = parsed;
|
sessionData.value = parsed;
|
||||||
|
|
@ -1058,7 +1094,7 @@ watch(
|
||||||
() => quotationFormData.value.customerBranchId,
|
() => quotationFormData.value.customerBranchId,
|
||||||
async (v) => {
|
async (v) => {
|
||||||
if (!v) return;
|
if (!v) return;
|
||||||
selectedWorker.value = [];
|
selectedWorkerItem.value = [];
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -1074,6 +1110,15 @@ watch(
|
||||||
|
|
||||||
const productServiceNodes = ref<ProductTree>([]);
|
const productServiceNodes = ref<ProductTree>([]);
|
||||||
|
|
||||||
|
watch(customerBranchOption, () => {
|
||||||
|
if (!customerBranchOption.value) return;
|
||||||
|
|
||||||
|
quotationFormData.value.contactName =
|
||||||
|
customerBranchOption.value.contactName || '';
|
||||||
|
quotationFormData.value.contactTel =
|
||||||
|
customerBranchOption.value.contactTel || '';
|
||||||
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => productServiceList.value,
|
() => productServiceList.value,
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -1081,6 +1126,13 @@ watch(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(customerBranchOption, () => {
|
||||||
|
if (!customerBranchOption.value) return;
|
||||||
|
|
||||||
|
quotationFormData.value.contactName = customerBranchOption.value.contactName;
|
||||||
|
quotationFormData.value.contactTel = customerBranchOption.value.contactTel;
|
||||||
|
});
|
||||||
|
|
||||||
// async function searchEmployee(text: string) {
|
// async function searchEmployee(text: string) {
|
||||||
// let query: string | undefined = text;
|
// let query: string | undefined = text;
|
||||||
// let pageSize = 50;
|
// let pageSize = 50;
|
||||||
|
|
@ -1102,7 +1154,19 @@ watch(
|
||||||
// }
|
// }
|
||||||
|
|
||||||
function storeDataLocal() {
|
function storeDataLocal() {
|
||||||
quotationFormData.value.productServiceList = productService.value;
|
const tempProductService = productService.value.map((v) => {
|
||||||
|
return {
|
||||||
|
...v,
|
||||||
|
vat: v.product[agentPrice ? 'agentPriceCalcVat' : 'calcVat']
|
||||||
|
? precisionRound(
|
||||||
|
((v.pricePerUnit * (1 + (config?.value.vat || 0.07)) * v.amount -
|
||||||
|
v.discount) /
|
||||||
|
(1 + (config?.value.vat || 0.07))) *
|
||||||
|
0.07,
|
||||||
|
)
|
||||||
|
: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'quotation-preview',
|
'quotation-preview',
|
||||||
|
|
@ -1111,7 +1175,7 @@ function storeDataLocal() {
|
||||||
codeInvoice: code.value,
|
codeInvoice: code.value,
|
||||||
codePayment: firstCodePayment.value,
|
codePayment: firstCodePayment.value,
|
||||||
...quotationFormData.value,
|
...quotationFormData.value,
|
||||||
productServiceList: productService.value,
|
productServiceList: tempProductService,
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
source: {
|
source: {
|
||||||
|
|
@ -1131,7 +1195,7 @@ function storeDataLocal() {
|
||||||
workName: quotationFormData.value.workName,
|
workName: quotationFormData.value.workName,
|
||||||
dueDate: quotationFormData.value.dueDate,
|
dueDate: quotationFormData.value.dueDate,
|
||||||
},
|
},
|
||||||
selectedWorker: selectedWorker.value,
|
selectedWorker: selectedWorkerItem.value,
|
||||||
createdBy: quotationFormState.value.createdBy('tha'),
|
createdBy: quotationFormState.value.createdBy('tha'),
|
||||||
agentPrice: agentPrice.value,
|
agentPrice: agentPrice.value,
|
||||||
},
|
},
|
||||||
|
|
@ -1216,10 +1280,10 @@ async function getWorkerFromCriteria(
|
||||||
if (!ret) return false; // error, do not close dialog
|
if (!ret) return false; // error, do not close dialog
|
||||||
|
|
||||||
const deduplicate = ret.result.filter(
|
const deduplicate = ret.result.filter(
|
||||||
(a) => !selectedWorker.value.find((b) => a.id === b.id),
|
(a) => !selectedWorkerItem.value.find((b) => a.id === b.id),
|
||||||
);
|
);
|
||||||
|
|
||||||
convertEmployeeToTable([...deduplicate, ...selectedWorker.value]);
|
convertEmployeeToTable([...deduplicate, ...selectedWorkerItem.value]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1515,6 +1579,7 @@ function covertToNode() {
|
||||||
v-model:contactor="quotationFormData.contactName"
|
v-model:contactor="quotationFormData.contactName"
|
||||||
v-model:telephone="quotationFormData.contactTel"
|
v-model:telephone="quotationFormData.contactTel"
|
||||||
v-model:due-date="quotationFormData.dueDate"
|
v-model:due-date="quotationFormData.dueDate"
|
||||||
|
v-model:seller-id="quotationFormData.sellerId"
|
||||||
>
|
>
|
||||||
<template #issue-info>
|
<template #issue-info>
|
||||||
<FormAbout
|
<FormAbout
|
||||||
|
|
@ -1525,6 +1590,7 @@ function covertToNode() {
|
||||||
v-model:customer-branch-id="
|
v-model:customer-branch-id="
|
||||||
quotationFormData.customerBranchId
|
quotationFormData.customerBranchId
|
||||||
"
|
"
|
||||||
|
v-model:customer-branch-option="customerBranchOption"
|
||||||
:readonly="readonly"
|
:readonly="readonly"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -1569,7 +1635,7 @@ function covertToNode() {
|
||||||
}}
|
}}
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<nav class="q-ml-auto">
|
<nav v-if="canAccess('quotation', 'edit')" class="q-ml-auto">
|
||||||
<AddButton
|
<AddButton
|
||||||
id="btn-add-worker"
|
id="btn-add-worker"
|
||||||
for="btn-add-worker"
|
for="btn-add-worker"
|
||||||
|
|
@ -1607,15 +1673,15 @@ function covertToNode() {
|
||||||
(v) =>
|
(v) =>
|
||||||
(quotationFormData.workerMax = Math.max(
|
(quotationFormData.workerMax = Math.max(
|
||||||
v,
|
v,
|
||||||
selectedWorker.length,
|
selectedWorkerItem.length,
|
||||||
))
|
))
|
||||||
"
|
"
|
||||||
:employee-amount="
|
:employee-amount="
|
||||||
quotationFormData.workerMax || selectedWorker.length
|
quotationFormData.workerMax || selectedWorkerItem.length
|
||||||
"
|
"
|
||||||
:readonly="readonly"
|
:readonly="readonly"
|
||||||
:rows="selectedWorkerItem"
|
:rows="selectedWorkerItem"
|
||||||
@delete="(i) => deleteItem(selectedWorker, i)"
|
@delete="(i) => deleteItem(selectedWorkerItem, i)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
|
|
@ -1746,7 +1812,9 @@ function covertToNode() {
|
||||||
:readonly="
|
:readonly="
|
||||||
{
|
{
|
||||||
quotation: quotationFormState.mode !== 'edit',
|
quotation: quotationFormState.mode !== 'edit',
|
||||||
invoice: false,
|
invoice:
|
||||||
|
isRoleInclude(['sale', 'head_of_sale']) ||
|
||||||
|
!canAccess('quotation', 'edit'),
|
||||||
accepted: true,
|
accepted: true,
|
||||||
}[view]
|
}[view]
|
||||||
"
|
"
|
||||||
|
|
@ -1857,10 +1925,10 @@ function covertToNode() {
|
||||||
installments: quotationFormData.paySplit,
|
installments: quotationFormData.paySplit,
|
||||||
},
|
},
|
||||||
'quotation-labor': {
|
'quotation-labor': {
|
||||||
name: selectedWorker.map(
|
name: selectedWorkerItem.map(
|
||||||
(v, i) =>
|
(v, i) =>
|
||||||
`${i + 1}. ` +
|
`${i + 1}. ` +
|
||||||
`${v.employeePassport.length !== 0 ? v.employeePassport[0].number + '_' : ''} ${v.namePrefix}.${v.firstNameEN ? `${v.firstNameEN} ${v.lastNameEN}` : `${v.firstName} ${v.lastName}`} `.toUpperCase(),
|
`${v.employeePassport.length !== 0 ? v.employeePassport[0].number + '_' : ''}${v.namePrefix}.${v.firstNameEN ? `${v.firstNameEN} ${v.lastNameEN}` : `${v.firstName} ${v.lastName}`} `.toUpperCase(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
@ -1950,6 +2018,11 @@ function covertToNode() {
|
||||||
view !== View.Receipt &&
|
view !== View.Receipt &&
|
||||||
view !== View.Complete
|
view !== View.Complete
|
||||||
"
|
"
|
||||||
|
:branch-id="quotationFull.registeredBranchId"
|
||||||
|
:readonly="
|
||||||
|
isRoleInclude(['sale', 'head_of_sale']) ||
|
||||||
|
!canAccess('quotation', 'edit')
|
||||||
|
"
|
||||||
:data="quotationFormState.source"
|
:data="quotationFormState.source"
|
||||||
v-model:first-code-payment="firstCodePayment"
|
v-model:first-code-payment="firstCodePayment"
|
||||||
@fetch-status="
|
@fetch-status="
|
||||||
|
|
@ -2088,7 +2161,14 @@ function covertToNode() {
|
||||||
:style="`background-color:hsla(var(--info-bg) / 0.07)`"
|
:style="`background-color:hsla(var(--info-bg) / 0.07)`"
|
||||||
>
|
>
|
||||||
<q-th auto-width>
|
<q-th auto-width>
|
||||||
<q-checkbox v-model="props.selected" />
|
<q-checkbox
|
||||||
|
v-if="
|
||||||
|
!quotationFormData.paySplit.every(
|
||||||
|
(p) => p.invoiceId,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
v-model="props.selected"
|
||||||
|
/>
|
||||||
</q-th>
|
</q-th>
|
||||||
<q-th
|
<q-th
|
||||||
v-for="col in props.cols"
|
v-for="col in props.cols"
|
||||||
|
|
@ -2118,8 +2198,6 @@ function covertToNode() {
|
||||||
|
|
||||||
installmentAmount = props.row.amount;
|
installmentAmount = props.row.amount;
|
||||||
view = View.Invoice;
|
view = View.Invoice;
|
||||||
|
|
||||||
console.log(code);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
|
|
@ -2281,6 +2359,7 @@ function covertToNode() {
|
||||||
class="q-ml-sm"
|
class="q-ml-sm"
|
||||||
v-if="
|
v-if="
|
||||||
view === View.Accepted &&
|
view === View.Accepted &&
|
||||||
|
canAccess('quotation', 'edit') &&
|
||||||
quotationFormData.quotationStatus === 'Issued'
|
quotationFormData.quotationStatus === 'Issued'
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
|
@ -2299,9 +2378,15 @@ function covertToNode() {
|
||||||
</MainButton>
|
</MainButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-if="view === View.InvoicePre">
|
<template
|
||||||
|
v-if="
|
||||||
|
view === View.InvoicePre &&
|
||||||
|
!quotationFormData.paySplit.every((p) => p.invoiceId)
|
||||||
|
"
|
||||||
|
>
|
||||||
<MainButton
|
<MainButton
|
||||||
solid
|
solid
|
||||||
|
:disabled="selectedInstallment.length === 0"
|
||||||
icon="mdi-account-multiple-check-outline"
|
icon="mdi-account-multiple-check-outline"
|
||||||
class="q-ml-sm"
|
class="q-ml-sm"
|
||||||
color="207 96% 32%"
|
color="207 96% 32%"
|
||||||
|
|
@ -2320,6 +2405,7 @@ function covertToNode() {
|
||||||
class="q-ml-sm"
|
class="q-ml-sm"
|
||||||
v-if="
|
v-if="
|
||||||
view === View.Invoice &&
|
view === View.Invoice &&
|
||||||
|
canAccess('quotation', 'edit') &&
|
||||||
((quotationFormData.quotationStatus !== 'PaymentPending' &&
|
((quotationFormData.quotationStatus !== 'PaymentPending' &&
|
||||||
quotationFormData.payCondition !== 'Full') ||
|
quotationFormData.payCondition !== 'Full') ||
|
||||||
quotationFormData.quotationStatus === 'Accepted') &&
|
quotationFormData.quotationStatus === 'Accepted') &&
|
||||||
|
|
@ -2327,7 +2413,6 @@ function covertToNode() {
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<MainButton
|
<MainButton
|
||||||
v-if="!hideBtnApproveInvoice"
|
|
||||||
solid
|
solid
|
||||||
icon="mdi-account-multiple-check-outline"
|
icon="mdi-account-multiple-check-outline"
|
||||||
color="207 96% 32%"
|
color="207 96% 32%"
|
||||||
|
|
@ -2347,6 +2432,7 @@ function covertToNode() {
|
||||||
style="gap: var(--size-2)"
|
style="gap: var(--size-2)"
|
||||||
v-if="
|
v-if="
|
||||||
(view === View.Quotation &&
|
(view === View.Quotation &&
|
||||||
|
canAccess('quotation', 'edit') &&
|
||||||
(quotationFormData.quotationStatus === 'Issued' ||
|
(quotationFormData.quotationStatus === 'Issued' ||
|
||||||
quotationFormData.quotationStatus === 'Expired')) ||
|
quotationFormData.quotationStatus === 'Expired')) ||
|
||||||
!quotationFormData.quotationStatus
|
!quotationFormData.quotationStatus
|
||||||
|
|
@ -2383,13 +2469,12 @@ function covertToNode() {
|
||||||
<!-- add employee quotation -->
|
<!-- add employee quotation -->
|
||||||
|
|
||||||
<QuotationFormWorkerSelect
|
<QuotationFormWorkerSelect
|
||||||
:preselect-worker="selectedWorker"
|
:preselect-worker="selectedWorkerItem"
|
||||||
:customerBranchId="quotationFormData.customerBranchId"
|
:customerBranchId="quotationFormData.customerBranchId"
|
||||||
v-model:open="pageState.employeeModal"
|
v-model:open="pageState.employeeModal"
|
||||||
v-model:new-worker-list="newWorkerList"
|
|
||||||
@success="
|
@success="
|
||||||
(v) => {
|
(v) => {
|
||||||
selectedWorker = v.worker;
|
combineWorker(v.newWorker, v.worker);
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
|
@ -2432,7 +2517,7 @@ function covertToNode() {
|
||||||
<!-- add Worker -->
|
<!-- add Worker -->
|
||||||
<QuotationFormWorkerAddDialog
|
<QuotationFormWorkerAddDialog
|
||||||
v-if="quotationFormState.source"
|
v-if="quotationFormState.source"
|
||||||
:disabled-worker-id="selectedWorker.map((v) => v.id)"
|
:disabled-worker-id="selectedWorkerItem.map((v) => v.id)"
|
||||||
:product-service-list="quotationFormState.source.productServiceList"
|
:product-service-list="quotationFormState.source.productServiceList"
|
||||||
:quotation-id="quotationFormState.source.id"
|
:quotation-id="quotationFormState.source.id"
|
||||||
:customer-branch-id="quotationFormState.source.customerBranchId"
|
:customer-branch-id="quotationFormState.source.customerBranchId"
|
||||||
|
|
|
||||||
|
|
@ -234,14 +234,14 @@ watch(
|
||||||
<section class="row q-col-gutter-sm col-12 items-center">
|
<section class="row q-col-gutter-sm col-12 items-center">
|
||||||
<SelectInput
|
<SelectInput
|
||||||
class="col-md-6 col-12"
|
class="col-md-6 col-12"
|
||||||
|
id="select-pay-type"
|
||||||
:label="$t('quotation.payType')"
|
:label="$t('quotation.payType')"
|
||||||
:option="
|
:option="
|
||||||
taskOrder
|
taskOrder
|
||||||
? payTypeOption.filter((v) => v.value === 'Full')
|
? payTypeOption.filter((v) => v.value === 'Full')
|
||||||
: payTypeOption
|
: payTypeOption
|
||||||
"
|
"
|
||||||
:readonly
|
:readonly="readonly || debitNote"
|
||||||
id="pay-type"
|
|
||||||
:model-value="payType"
|
:model-value="payType"
|
||||||
@update:model-value="
|
@update:model-value="
|
||||||
(v) => {
|
(v) => {
|
||||||
|
|
@ -275,6 +275,7 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
<q-input
|
<q-input
|
||||||
v-model="paySplitCount"
|
v-model="paySplitCount"
|
||||||
|
id="input-pay-split-count"
|
||||||
:readonly="readonly || payType === 'Split'"
|
:readonly="readonly || payType === 'Split'"
|
||||||
class="col-3"
|
class="col-3"
|
||||||
type="number"
|
type="number"
|
||||||
|
|
@ -311,6 +312,7 @@ watch(
|
||||||
<q-input
|
<q-input
|
||||||
:readonly="readonly"
|
:readonly="readonly"
|
||||||
:label="$t('general.name')"
|
:label="$t('general.name')"
|
||||||
|
:id="`input-period-name-${i}`"
|
||||||
v-if="payType === 'SplitCustom'"
|
v-if="payType === 'SplitCustom'"
|
||||||
v-model="period.name"
|
v-model="period.name"
|
||||||
class="col q-mx-sm"
|
class="col q-mx-sm"
|
||||||
|
|
@ -320,6 +322,7 @@ watch(
|
||||||
<q-input
|
<q-input
|
||||||
:readonly="readonly || payType === 'Split'"
|
:readonly="readonly || payType === 'Split'"
|
||||||
class="col q-mx-sm"
|
class="col q-mx-sm"
|
||||||
|
:id="`input-period-amount-${i}`"
|
||||||
:label="$t('quotation.amount')"
|
:label="$t('quotation.amount')"
|
||||||
:model-value="
|
:model-value="
|
||||||
amount4Show[i] || commaInput(period.amount.toString())
|
amount4Show[i] || commaInput(period.amount.toString())
|
||||||
|
|
@ -377,6 +380,7 @@ watch(
|
||||||
|
|
||||||
<DatePicker
|
<DatePicker
|
||||||
v-if="payType === 'BillFull'"
|
v-if="payType === 'BillFull'"
|
||||||
|
id="datepicker-bill-date"
|
||||||
:readonly
|
:readonly
|
||||||
class="col-12"
|
class="col-12"
|
||||||
:label="$t('quotation.callDueDate')"
|
:label="$t('quotation.callDueDate')"
|
||||||
|
|
@ -446,7 +450,9 @@ watch(
|
||||||
<span class="q-ml-auto">
|
<span class="q-ml-auto">
|
||||||
{{
|
{{
|
||||||
formatNumberDecimal(
|
formatNumberDecimal(
|
||||||
summaryPrice.totalPrice - summaryPrice.totalDiscount,
|
summaryPrice.totalPrice -
|
||||||
|
summaryPrice.totalDiscount -
|
||||||
|
summaryPrice.vatExcluded,
|
||||||
2,
|
2,
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
@ -482,7 +488,11 @@ watch(
|
||||||
<div class="q-pa-sm row surface-2 items-center text-weight-bold">
|
<div class="q-pa-sm row surface-2 items-center text-weight-bold">
|
||||||
{{ $t('quotation.totalPriceBaht') }}
|
{{ $t('quotation.totalPriceBaht') }}
|
||||||
|
|
||||||
<span class="q-ml-auto" style="color: var(--brand-1)">
|
<span
|
||||||
|
class="q-ml-auto"
|
||||||
|
style="color: var(--brand-1)"
|
||||||
|
id="value-final-price"
|
||||||
|
>
|
||||||
{{
|
{{
|
||||||
payType === 'SplitCustom' && view === View.Invoice
|
payType === 'SplitCustom' && view === View.Invoice
|
||||||
? formatNumberDecimal(Math.max(installmentAmount || 0, 0), 2) || 0
|
? formatNumberDecimal(Math.max(installmentAmount || 0, 0), 2) || 0
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import DatePicker from 'src/components/shared/DatePicker.vue';
|
import DatePicker from 'src/components/shared/DatePicker.vue';
|
||||||
|
import SelectUser from 'src/components/shared/select/SelectUser.vue';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
readonly: boolean;
|
readonly: boolean;
|
||||||
|
|
@ -13,6 +14,7 @@ const contactor = defineModel<string>('contactor', { required: true });
|
||||||
const telephone = defineModel<string>('telephone', { required: true });
|
const telephone = defineModel<string>('telephone', { required: true });
|
||||||
const dueDate = defineModel<Date | string>('dueDate', { required: true });
|
const dueDate = defineModel<Date | string>('dueDate', { required: true });
|
||||||
const createdAt = defineModel<Date | string>('createdAt');
|
const createdAt = defineModel<Date | string>('createdAt');
|
||||||
|
const sellerId = defineModel<string>('sellerId', { required: true });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -95,5 +97,11 @@ const createdAt = defineModel<Date | string>('createdAt');
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
/>
|
/>
|
||||||
|
<SelectUser
|
||||||
|
:label="$t('preview.seller')"
|
||||||
|
v-model:value="sellerId"
|
||||||
|
:readonly
|
||||||
|
class="col-12 col-md-2"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,8 @@ const emit = defineEmits<{
|
||||||
const selectedProductGroup = defineModel<string>('selectedProductGroup', {
|
const selectedProductGroup = defineModel<string>('selectedProductGroup', {
|
||||||
default: '',
|
default: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const selectedProductGroupOption = ref<ProductGroup | undefined>();
|
||||||
const model = defineModel<boolean>();
|
const model = defineModel<boolean>();
|
||||||
const inputSearch = defineModel<string>('inputSearch');
|
const inputSearch = defineModel<string>('inputSearch');
|
||||||
const productGroup = defineModel<ProductGroup[]>('productGroup', {
|
const productGroup = defineModel<ProductGroup[]>('productGroup', {
|
||||||
|
|
@ -66,21 +68,21 @@ const serviceList = defineModel<Partial<Record<ProductGroupId, Service[]>>>(
|
||||||
);
|
);
|
||||||
|
|
||||||
const priceDisplay = computed(() => ({
|
const priceDisplay = computed(() => ({
|
||||||
price: !isRoleInclude(['sale_agent']),
|
// price: !isRoleInclude(['sale_agent']),
|
||||||
|
price: true,
|
||||||
agentPrice: isRoleInclude([
|
agentPrice: isRoleInclude([
|
||||||
'admin',
|
|
||||||
'head_of_admin',
|
|
||||||
'head_of_sale',
|
|
||||||
'system',
|
'system',
|
||||||
'owner',
|
'head_of_admin',
|
||||||
|
'admin',
|
||||||
|
'executive',
|
||||||
'accountant',
|
'accountant',
|
||||||
'sale_agent',
|
'head_of_sale',
|
||||||
]),
|
]),
|
||||||
serviceCharge: isRoleInclude([
|
serviceCharge: isRoleInclude([
|
||||||
'admin',
|
|
||||||
'head_of_admin',
|
|
||||||
'system',
|
'system',
|
||||||
'owner',
|
'head_of_admin',
|
||||||
|
'admin',
|
||||||
|
'executive',
|
||||||
'accountant',
|
'accountant',
|
||||||
]),
|
]),
|
||||||
}));
|
}));
|
||||||
|
|
@ -569,14 +571,18 @@ watch(
|
||||||
{{
|
{{
|
||||||
productGroup.find(
|
productGroup.find(
|
||||||
(g) => g.id === selectedProductGroup,
|
(g) => g.id === selectedProductGroup,
|
||||||
)?.name || '-'
|
)?.name ||
|
||||||
|
selectedProductGroupOption?.name ||
|
||||||
|
'-'
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-caption app-text-muted">
|
<span class="text-caption app-text-muted">
|
||||||
{{
|
{{
|
||||||
productGroup.find(
|
productGroup.find(
|
||||||
(g) => g.id === selectedProductGroup,
|
(g) => g.id === selectedProductGroup,
|
||||||
)?.code || '-'
|
)?.code ||
|
||||||
|
selectedProductGroupOption?.code ||
|
||||||
|
'-'
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -862,13 +868,13 @@ watch(
|
||||||
<span class="q-pr-sm">
|
<span class="q-pr-sm">
|
||||||
{{ $t('productService.group.title') }}
|
{{ $t('productService.group.title') }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<SelectProductGroup
|
<SelectProductGroup
|
||||||
class="col-md-4 col-12"
|
class="col-md-4 col-12"
|
||||||
:class="{ 'q-mb-sm': $q.screen.lt.md }"
|
:class="{ 'q-mb-sm': $q.screen.lt.md }"
|
||||||
id="product-group-select"
|
id="product-group-select"
|
||||||
clearable
|
clearable
|
||||||
v-model:value="selectedProductGroup"
|
v-model:value="selectedProductGroup"
|
||||||
|
v-model:value-option="selectedProductGroupOption"
|
||||||
:placeholder="
|
:placeholder="
|
||||||
!selectedProductGroup
|
!selectedProductGroup
|
||||||
? $t('general.select', {
|
? $t('general.select', {
|
||||||
|
|
|
||||||
|
|
@ -341,12 +341,13 @@ watch(() => state.search, getWorkerList);
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style="display: inline-block; margin-inline: auto"
|
style="display: inline-block; margin-inline: auto"
|
||||||
v-if="workerList.length === 0"
|
v-if="workerList.length === 0 && state.search"
|
||||||
>
|
>
|
||||||
<NoData :not-found="!!state.search" />
|
<NoData :not-found="!!state.search" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TableWorker
|
<TableWorker
|
||||||
|
v-else
|
||||||
v-model:selected="workerSelected"
|
v-model:selected="workerSelected"
|
||||||
:rows="workerList"
|
:rows="workerList"
|
||||||
:disabledWorkerId
|
:disabledWorkerId
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import useOcrStore from 'stores/ocr';
|
||||||
|
|
||||||
// NOTE: Import Components
|
// NOTE: Import Components
|
||||||
import {
|
import {
|
||||||
|
AddButton,
|
||||||
SaveButton,
|
SaveButton,
|
||||||
EditButton,
|
EditButton,
|
||||||
UndoButton,
|
UndoButton,
|
||||||
|
|
@ -53,6 +54,9 @@ import { SideMenu } from 'src/components';
|
||||||
import BasicInformation from 'components/03_customer-management/employee/BasicInformation.vue';
|
import BasicInformation from 'components/03_customer-management/employee/BasicInformation.vue';
|
||||||
import { AddressForm } from 'src/components/form';
|
import { AddressForm } from 'src/components/form';
|
||||||
import ExpirationDate from 'src/components/03_customer-management/ExpirationDate.vue';
|
import ExpirationDate from 'src/components/03_customer-management/ExpirationDate.vue';
|
||||||
|
import FormEmployeeHealthCheck from 'src/components/03_customer-management/FormEmployeeHealthCheck.vue';
|
||||||
|
import FormEmployeeWorkHistory from 'src/components/03_customer-management/FormEmployeeWorkHistory.vue';
|
||||||
|
import FormEmployeeOther from 'src/components/03_customer-management/FormEmployeeOther.vue';
|
||||||
|
|
||||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
||||||
|
|
||||||
|
|
@ -109,7 +113,7 @@ const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
customerBranchId?: string;
|
customerBranchId?: string;
|
||||||
disabledWorkerId?: string[];
|
disabledWorkerId?: string[];
|
||||||
preselectWorker?: Employee[];
|
preselectWorker?: (Employee & { workerNew: boolean })[];
|
||||||
}>(),
|
}>(),
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
@ -129,7 +133,7 @@ const optionStore = useOptionStore();
|
||||||
const employeeStore = useEmployeeStore();
|
const employeeStore = useEmployeeStore();
|
||||||
|
|
||||||
const open = defineModel<boolean>('open', { default: false });
|
const open = defineModel<boolean>('open', { default: false });
|
||||||
const newWorkerList = defineModel<
|
const newWorkerList = ref<
|
||||||
(EmployeeWorker & {
|
(EmployeeWorker & {
|
||||||
attachment?: {
|
attachment?: {
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|
@ -139,7 +143,7 @@ const newWorkerList = defineModel<
|
||||||
_meta?: Record<string, any>;
|
_meta?: Record<string, any>;
|
||||||
}[];
|
}[];
|
||||||
})[]
|
})[]
|
||||||
>('newWorkerList', { default: [] });
|
>([]);
|
||||||
const workerSelected = ref<Employee[]>([]);
|
const workerSelected = ref<Employee[]>([]);
|
||||||
const workerList = ref<Employee[]>([]);
|
const workerList = ref<Employee[]>([]);
|
||||||
const importWorkerCriteria = ref<{
|
const importWorkerCriteria = ref<{
|
||||||
|
|
@ -204,7 +208,13 @@ function getEmployeeImageUrl(item: Employee) {
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
if (props.preselectWorker) {
|
if (props.preselectWorker) {
|
||||||
workerSelected.value = JSON.parse(JSON.stringify(props.preselectWorker));
|
workerSelected.value = JSON.parse(
|
||||||
|
JSON.stringify(props.preselectWorker.filter((v) => !v.workerNew)),
|
||||||
|
);
|
||||||
|
|
||||||
|
newWorkerList.value = JSON.parse(
|
||||||
|
JSON.stringify(props.preselectWorker.filter((v) => v.workerNew)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
getWorkerList();
|
getWorkerList();
|
||||||
}
|
}
|
||||||
|
|
@ -604,11 +614,14 @@ watch(
|
||||||
solid
|
solid
|
||||||
id="btn-success"
|
id="btn-success"
|
||||||
@click="
|
@click="
|
||||||
emits('success', {
|
() => {
|
||||||
worker: workerSelected,
|
$emit('success', {
|
||||||
newWorker: newWorkerList,
|
worker: workerSelected,
|
||||||
}),
|
newWorker: newWorkerList,
|
||||||
(open = false)
|
});
|
||||||
|
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ $t('general.select', { msg: $t('quotation.employeeList') }) }}
|
{{ $t('general.select', { msg: $t('quotation.employeeList') }) }}
|
||||||
|
|
@ -630,9 +643,11 @@ watch(
|
||||||
if (employeeFormState.currentTab === 'personalInfo') {
|
if (employeeFormState.currentTab === 'personalInfo') {
|
||||||
const currentEmployeeId =
|
const currentEmployeeId =
|
||||||
await employeeFormStore.submitPersonal(onCreateImageList);
|
await employeeFormStore.submitPersonal(onCreateImageList);
|
||||||
quotationForm.injectNewEmployee({
|
newWorkerList.push(
|
||||||
data: { ...currentFromDataEmployee, id: currentEmployeeId },
|
quotationForm.injectNewEmployee({
|
||||||
});
|
data: { ...currentFromDataEmployee, id: currentEmployeeId },
|
||||||
|
}),
|
||||||
|
);
|
||||||
employeeFormState.isEmployeeEdit = false;
|
employeeFormState.isEmployeeEdit = false;
|
||||||
employeeFormState.dialogType = 'info';
|
employeeFormState.dialogType = 'info';
|
||||||
}
|
}
|
||||||
|
|
@ -663,6 +678,7 @@ watch(
|
||||||
:show="
|
:show="
|
||||||
() => {
|
() => {
|
||||||
employeeFormStore.resetFormDataEmployee(true);
|
employeeFormStore.resetFormDataEmployee(true);
|
||||||
|
setCurrentBranchId();
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
:before-close="
|
:before-close="
|
||||||
|
|
@ -1035,6 +1051,7 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BasicInformation
|
<BasicInformation
|
||||||
|
disable-customer-select
|
||||||
no-action
|
no-action
|
||||||
id="form-information"
|
id="form-information"
|
||||||
prefix-id="form-employee"
|
prefix-id="form-employee"
|
||||||
|
|
@ -1455,6 +1472,7 @@ watch(
|
||||||
v-model:remark="meta.remark"
|
v-model:remark="meta.remark"
|
||||||
v-model:worker-type="meta.workerType"
|
v-model:worker-type="meta.workerType"
|
||||||
v-model:number="meta.number"
|
v-model:number="meta.number"
|
||||||
|
v-model:report-date="meta.reportDate"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<NoticeJobEmployment v-if="mode === 'noticeJobEmployment'" />
|
<NoticeJobEmployment v-if="mode === 'noticeJobEmployment'" />
|
||||||
|
|
@ -1681,6 +1699,7 @@ watch(
|
||||||
v-model:remark="value.remark"
|
v-model:remark="value.remark"
|
||||||
v-model:worker-type="value.workerType"
|
v-model:worker-type="value.workerType"
|
||||||
v-model:number="value.number"
|
v-model:number="value.number"
|
||||||
|
v-model:report-date="value.reportDate"
|
||||||
>
|
>
|
||||||
<template v-slot:expiryDate>
|
<template v-slot:expiryDate>
|
||||||
{{ $t('general.expirationDate') }} :
|
{{ $t('general.expirationDate') }} :
|
||||||
|
|
@ -1991,8 +2010,8 @@ watch(
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(
|
:deep(
|
||||||
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
|
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
|
||||||
) {
|
) {
|
||||||
color: var(--brand-1);
|
color: var(--brand-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2009,9 +2028,9 @@ watch(
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(
|
:deep(
|
||||||
.q-item.q-item-type.row.no-wrap.q-item--dense.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable.surface-1
|
.q-item.q-item-type.row.no-wrap.q-item--dense.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable.surface-1
|
||||||
.q-focus-helper
|
.q-focus-helper
|
||||||
) {
|
) {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import {
|
||||||
QuotationPayload,
|
QuotationPayload,
|
||||||
QuotationFull,
|
QuotationFull,
|
||||||
EmployeeWorker,
|
EmployeeWorker,
|
||||||
|
PayCondition,
|
||||||
} from 'src/stores/quotations/types';
|
} from 'src/stores/quotations/types';
|
||||||
import { Employee } from 'src/stores/employee/types';
|
import { Employee } from 'src/stores/employee/types';
|
||||||
|
|
||||||
|
|
@ -29,7 +30,7 @@ export const DEFAULT_DATA: QuotationPayload = {
|
||||||
payBillDate: new Date(),
|
payBillDate: new Date(),
|
||||||
paySplit: [],
|
paySplit: [],
|
||||||
paySplitCount: 0,
|
paySplitCount: 0,
|
||||||
payCondition: 'Full',
|
payCondition: PayCondition.Full,
|
||||||
dueDate: new Date(Date.now() + 86400000),
|
dueDate: new Date(Date.now() + 86400000),
|
||||||
discount: 0,
|
discount: 0,
|
||||||
contactTel: '',
|
contactTel: '',
|
||||||
|
|
@ -40,6 +41,7 @@ export const DEFAULT_DATA: QuotationPayload = {
|
||||||
status: 'CREATED',
|
status: 'CREATED',
|
||||||
remark: '#[quotation-labor]<br/><br/>#[quotation-payment]',
|
remark: '#[quotation-labor]<br/><br/>#[quotation-payment]',
|
||||||
agentPrice: false,
|
agentPrice: false,
|
||||||
|
sellerId: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_DATA_INVOICE: InvoicePayload = {
|
const DEFAULT_DATA_INVOICE: InvoicePayload = {
|
||||||
|
|
@ -67,6 +69,7 @@ export const useQuotationForm = defineStore('form-quotation', () => {
|
||||||
file?: File;
|
file?: File;
|
||||||
_meta?: Record<string, any>;
|
_meta?: Record<string, any>;
|
||||||
}[];
|
}[];
|
||||||
|
workerNew: boolean;
|
||||||
})[]
|
})[]
|
||||||
>([]);
|
>([]);
|
||||||
|
|
||||||
|
|
@ -218,7 +221,7 @@ export const useQuotationForm = defineStore('form-quotation', () => {
|
||||||
},
|
},
|
||||||
callback?: () => void,
|
callback?: () => void,
|
||||||
) {
|
) {
|
||||||
newWorkerList.value.push({
|
const temp = {
|
||||||
//passportNo: obj.data.passportNo,
|
//passportNo: obj.data.passportNo,
|
||||||
//documentExpireDate: obj.data.documentExpireDate,
|
//documentExpireDate: obj.data.documentExpireDate,
|
||||||
id: obj.data.id,
|
id: obj.data.id,
|
||||||
|
|
@ -233,9 +236,12 @@ export const useQuotationForm = defineStore('form-quotation', () => {
|
||||||
gender: obj.data.gender,
|
gender: obj.data.gender,
|
||||||
dateOfBirth: obj.data.dateOfBirth,
|
dateOfBirth: obj.data.dateOfBirth,
|
||||||
attachment: obj.data.attachment,
|
attachment: obj.data.attachment,
|
||||||
});
|
workerNew: true,
|
||||||
|
};
|
||||||
|
|
||||||
callback?.();
|
callback?.();
|
||||||
|
|
||||||
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
function dialogDelete(callback: () => void) {
|
function dialogDelete(callback: () => void) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { onMounted, nextTick, ref, watch } from 'vue';
|
import { onMounted, nextTick, ref, watch, toRaw } from 'vue';
|
||||||
import { precisionRound } from 'src/utils/arithmetic';
|
import { precisionRound } from 'src/utils/arithmetic';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import ThaiBahtText from 'thai-baht-text';
|
import ThaiBahtText from 'thai-baht-text';
|
||||||
|
|
@ -175,6 +175,8 @@ enum View {
|
||||||
const view = ref<View>(View.Quotation);
|
const view = ref<View>(View.Quotation);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
await configStore.getConfig();
|
||||||
|
|
||||||
const currentDocumentType = new URL(window.location.href).searchParams.get(
|
const currentDocumentType = new URL(window.location.href).searchParams.get(
|
||||||
'type',
|
'type',
|
||||||
);
|
);
|
||||||
|
|
@ -259,18 +261,6 @@ onMounted(async () => {
|
||||||
productList.value =
|
productList.value =
|
||||||
(data?.value?.productServiceList ?? data.value?.productServiceList).map(
|
(data?.value?.productServiceList ?? data.value?.productServiceList).map(
|
||||||
(v) => {
|
(v) => {
|
||||||
const originalPrice = v.pricePerUnit;
|
|
||||||
const finalPriceWithVat = precisionRound(
|
|
||||||
originalPrice * (1 + (config.value?.vat || 0.07)),
|
|
||||||
);
|
|
||||||
const finalPriceNoVat =
|
|
||||||
finalPriceWithVat / (1 + (config.value?.vat || 0.07));
|
|
||||||
|
|
||||||
const price = finalPriceNoVat * v.amount - v.discount;
|
|
||||||
const vat =
|
|
||||||
(finalPriceNoVat * v.amount - v.discount) *
|
|
||||||
(config.value?.vat || 0.07);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: v.product.id,
|
id: v.product.id,
|
||||||
code: v.product.code,
|
code: v.product.code,
|
||||||
|
|
@ -279,8 +269,8 @@ onMounted(async () => {
|
||||||
pricePerUnit: v.pricePerUnit || 0,
|
pricePerUnit: v.pricePerUnit || 0,
|
||||||
discount: v.discount || 0,
|
discount: v.discount || 0,
|
||||||
vat: v.vat || 0,
|
vat: v.vat || 0,
|
||||||
value: precisionRound(price + (v.product.calcVat ? vat : 0)),
|
value: 0,
|
||||||
calcVat: v.product.calcVat,
|
calcVat: v.vat > 0,
|
||||||
product: v.product,
|
product: v.product,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
@ -292,23 +282,17 @@ onMounted(async () => {
|
||||||
[]
|
[]
|
||||||
).reduce(
|
).reduce(
|
||||||
(a, c) => {
|
(a, c) => {
|
||||||
const originalPrice = c.pricePerUnit;
|
const calcVat = c.vat > 0;
|
||||||
const finalPriceWithVat = precisionRound(
|
const vatFactor = calcVat ? (config.value?.vat ?? 0.07) : 0;
|
||||||
originalPrice * (1 + (config.value?.vat || 0.07)),
|
const pricePerUnit =
|
||||||
);
|
precisionRound(c.pricePerUnit * (1 + vatFactor)) / (1 + vatFactor);
|
||||||
const finalPriceNoVat =
|
const price =
|
||||||
finalPriceWithVat / (1 + (config.value?.vat || 0.07));
|
(pricePerUnit * c.amount * (1 + vatFactor) - c.discount) /
|
||||||
|
(1 + vatFactor);
|
||||||
|
|
||||||
const price = finalPriceNoVat * c.amount;
|
a.totalPrice = precisionRound(a.totalPrice + price + c.discount);
|
||||||
const vat =
|
|
||||||
(finalPriceNoVat * c.amount - c.discount) * (config.value?.vat || 0.07);
|
|
||||||
|
|
||||||
const calcVat =
|
|
||||||
c.product[agentPrice.value ? 'agentPriceCalcVat' : 'calcVat'];
|
|
||||||
|
|
||||||
a.totalPrice = precisionRound(a.totalPrice + price);
|
|
||||||
a.totalDiscount = precisionRound(a.totalDiscount + Number(c.discount));
|
a.totalDiscount = precisionRound(a.totalDiscount + Number(c.discount));
|
||||||
a.vat = calcVat ? precisionRound(a.vat + vat) : a.vat;
|
a.vat = calcVat ? precisionRound(a.vat + c.vat) : a.vat;
|
||||||
a.vatExcluded = calcVat
|
a.vatExcluded = calcVat
|
||||||
? a.vatExcluded
|
? a.vatExcluded
|
||||||
: precisionRound(a.vatExcluded + price);
|
: precisionRound(a.vatExcluded + price);
|
||||||
|
|
@ -334,16 +318,12 @@ onMounted(async () => {
|
||||||
|
|
||||||
function calcPrice(c: Product) {
|
function calcPrice(c: Product) {
|
||||||
const originalPrice = c.pricePerUnit;
|
const originalPrice = c.pricePerUnit;
|
||||||
const finalPriceWithVat = precisionRound(
|
const finalPricePerUnit = precisionRound(
|
||||||
originalPrice + originalPrice * (config.value?.vat || 0.07),
|
originalPrice +
|
||||||
|
(c.calcVat ? originalPrice * (config.value?.vat || 0.07) : 0),
|
||||||
);
|
);
|
||||||
const finalPriceNoVat = finalPriceWithVat / (1 + (config.value?.vat || 0.07));
|
const price = finalPricePerUnit * c.amount - c.discount;
|
||||||
|
return precisionRound(price);
|
||||||
const price = finalPriceNoVat * c.amount - c.discount;
|
|
||||||
const vat = c.product[agentPrice.value ? 'agentPriceCalcVat' : 'calcVat']
|
|
||||||
? (finalPriceNoVat * c.amount - c.discount) * (config.value?.vat || 0.07)
|
|
||||||
: 0;
|
|
||||||
return precisionRound(price + vat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function closeTab() {
|
async function closeTab() {
|
||||||
|
|
@ -427,31 +407,15 @@ function print() {
|
||||||
<td>{{ v.detail }}</td>
|
<td>{{ v.detail }}</td>
|
||||||
<td style="text-align: right">{{ v.amount }}</td>
|
<td style="text-align: right">{{ v.amount }}</td>
|
||||||
<td style="text-align: right">
|
<td style="text-align: right">
|
||||||
{{
|
{{ formatNumberDecimal(v.pricePerUnit, 2) }}
|
||||||
formatNumberDecimal(
|
|
||||||
v.pricePerUnit +
|
|
||||||
(v.product[agentPrice ? 'agentPriceCalcVat' : 'calcVat']
|
|
||||||
? v.pricePerUnit * (config?.vat || 0.07)
|
|
||||||
: 0),
|
|
||||||
2,
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</td>
|
</td>
|
||||||
<td style="text-align: right">
|
<td style="text-align: right">
|
||||||
{{ formatNumberDecimal(v.discount, 2) }}
|
<template v-if="v.discount !== 0">
|
||||||
|
{{ formatNumberDecimal(v.discount, 2) }} ฿
|
||||||
|
</template>
|
||||||
</td>
|
</td>
|
||||||
<td style="text-align: right">
|
<td style="text-align: right">
|
||||||
{{
|
{{ Math.round((v.vat > 0 ? config?.vat || 0.07 : 0) * 100) }}%
|
||||||
formatNumberDecimal(
|
|
||||||
v.product[agentPrice ? 'agentPriceCalcVat' : 'calcVat']
|
|
||||||
? precisionRound(
|
|
||||||
(v.pricePerUnit * v.amount - v.discount) *
|
|
||||||
(config?.vat || 0.07),
|
|
||||||
)
|
|
||||||
: 0,
|
|
||||||
2,
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</td>
|
</td>
|
||||||
<td style="text-align: right">
|
<td style="text-align: right">
|
||||||
{{ formatNumberDecimal(calcPrice(v), 2) }}
|
{{ formatNumberDecimal(calcPrice(v), 2) }}
|
||||||
|
|
@ -511,7 +475,9 @@ function print() {
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
{{
|
{{
|
||||||
formatNumberDecimal(
|
formatNumberDecimal(
|
||||||
summaryPrice.totalPrice - summaryPrice.totalDiscount,
|
summaryPrice.totalPrice -
|
||||||
|
summaryPrice.totalDiscount -
|
||||||
|
summaryPrice.vatExcluded,
|
||||||
2,
|
2,
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
@ -600,7 +566,7 @@ function print() {
|
||||||
details?.worker.map(
|
details?.worker.map(
|
||||||
(v, i) =>
|
(v, i) =>
|
||||||
`${i + 1}. ` +
|
`${i + 1}. ` +
|
||||||
`${v.namePrefix}. ${v.firstNameEN ? `${v.firstNameEN} ${v.lastNameEN}` : `${v.firstName} ${v.lastName}`} `.toUpperCase(),
|
`${v.employeePassport.length !== 0 ? v.employeePassport[0].number + '_' : ''}${v.namePrefix}. ${v.firstNameEN ? `${v.firstNameEN} ${v.lastNameEN}` : `${v.firstName} ${v.lastName}`} `.toUpperCase(),
|
||||||
) || [],
|
) || [],
|
||||||
},
|
},
|
||||||
}) || '-'
|
}) || '-'
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { dateFormat } from 'src/utils/datetime';
|
||||||
|
|
||||||
// NOTE: Import stores
|
// NOTE: Import stores
|
||||||
import { formatAddress } from 'src/utils/address';
|
import { formatAddress } from 'src/utils/address';
|
||||||
|
import { getCustomerName } from 'src/stores/utils';
|
||||||
|
|
||||||
// NOTE Import Types
|
// NOTE Import Types
|
||||||
import { Branch } from 'src/stores/branch/types';
|
import { Branch } from 'src/stores/branch/types';
|
||||||
|
|
@ -78,12 +79,15 @@ function titleMode(mode: View): string {
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
<span>เลขประจำตัวผู้เสียภาษี {{ branch.taxNo }}</span>
|
<span>{{ $t('branch.form.taxNo') }} {{ branch.taxNo }}</span>
|
||||||
<span>เบอร์โทร {{ branch.telephoneNo }}</span>
|
<span>{{ $t('taskOrder.telephone') }} {{ branch.telephoneNo }}</span>
|
||||||
<span>{{ branch.webUrl }}</span>
|
<span>{{ branch.webUrl }}</span>
|
||||||
</article>
|
</article>
|
||||||
<article>
|
<article>
|
||||||
<b>{{ $t('quotation.customer') }}</b>
|
<b>{{ $t('quotation.customer') }}</b>
|
||||||
|
<div>
|
||||||
|
{{ getCustomerName(customer, { noCode: true, locale: 'tha' }) }}
|
||||||
|
</div>
|
||||||
<span>
|
<span>
|
||||||
{{
|
{{
|
||||||
formatAddress({
|
formatAddress({
|
||||||
|
|
@ -101,8 +105,18 @@ function titleMode(mode: View): string {
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
<span>เลขประจำตัวผู้เสียภาษี {{ customer.citizenId }}</span>
|
<span>
|
||||||
<span>เบอร์โทร {{ customer.telephoneNo }}</span>
|
{{
|
||||||
|
customer.customer.customerType === 'CORP'
|
||||||
|
? `${$t('customer.form.legalPersonNo')} `
|
||||||
|
: `${$t('customer.form.taxpayyerNo')} `
|
||||||
|
}}{{
|
||||||
|
customer.customer.customerType === 'CORP'
|
||||||
|
? customer.codeCustomer
|
||||||
|
: customer.citizenId
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
<span>{{ $t('taskOrder.telephone') }} {{ customer.telephoneNo }}</span>
|
||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
<section class="detail-quotation-info">
|
<section class="detail-quotation-info">
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@ const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
isEdit?: boolean;
|
isEdit?: boolean;
|
||||||
|
hideAction?: boolean;
|
||||||
|
hideDelete?: boolean;
|
||||||
|
|
||||||
dataId?: string;
|
dataId?: string;
|
||||||
}>(),
|
}>(),
|
||||||
|
|
@ -80,6 +82,7 @@ const emit = defineEmits<{
|
||||||
(e: 'addImage'): void;
|
(e: 'addImage'): void;
|
||||||
(e: 'removeImage'): void;
|
(e: 'removeImage'): void;
|
||||||
(e: 'submitImage', name: string): void;
|
(e: 'submitImage', name: string): void;
|
||||||
|
(e: 'deleteAttachment', name: string): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const data = defineModel<InstitutionPayload>('data', {
|
const data = defineModel<InstitutionPayload>('data', {
|
||||||
|
|
@ -119,6 +122,9 @@ const formBankBook = defineModel<BankBook[]>('formBankBook', {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
const attachment = defineModel<File[]>('attachment');
|
||||||
|
const attachmentList =
|
||||||
|
defineModel<{ name: string; url: string }[]>('attachmentList');
|
||||||
|
|
||||||
function viewImage() {
|
function viewImage() {
|
||||||
imageState.imageDialog = true;
|
imageState.imageDialog = true;
|
||||||
|
|
@ -346,6 +352,7 @@ watch(
|
||||||
v-model:contact-name="data.contactName"
|
v-model:contact-name="data.contactName"
|
||||||
v-model:email="data.contactEmail"
|
v-model:email="data.contactEmail"
|
||||||
v-model:contact-tel="data.contactTel"
|
v-model:contact-tel="data.contactTel"
|
||||||
|
v-model:attachment="attachment"
|
||||||
/>
|
/>
|
||||||
<AddressForm
|
<AddressForm
|
||||||
id="agencies-form-address-info"
|
id="agencies-form-address-info"
|
||||||
|
|
@ -411,6 +418,7 @@ watch(
|
||||||
:prefix="data.name"
|
:prefix="data.name"
|
||||||
hide-fade
|
hide-fade
|
||||||
use-toggle
|
use-toggle
|
||||||
|
:readonly="hideAction"
|
||||||
:active="data.status !== 'INACTIVE'"
|
:active="data.status !== 'INACTIVE'"
|
||||||
:toggle-title="$t('status.title')"
|
:toggle-title="$t('status.title')"
|
||||||
:icon="'ph-building-office'"
|
:icon="'ph-building-office'"
|
||||||
|
|
@ -450,7 +458,7 @@ watch(
|
||||||
style="position: absolute; z-index: 999; top: 0; right: 0"
|
style="position: absolute; z-index: 999; top: 0; right: 0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="data.status !== 'INACTIVE'"
|
v-if="data.status !== 'INACTIVE' && !hideAction"
|
||||||
class="surface-1 row rounded"
|
class="surface-1 row rounded"
|
||||||
>
|
>
|
||||||
<UndoButton
|
<UndoButton
|
||||||
|
|
@ -484,7 +492,7 @@ watch(
|
||||||
type="button"
|
type="button"
|
||||||
/>
|
/>
|
||||||
<DeleteButton
|
<DeleteButton
|
||||||
v-if="!isEdit"
|
v-if="!isEdit && !hideDelete"
|
||||||
id="btn-info-basic-delete"
|
id="btn-info-basic-delete"
|
||||||
icon-only
|
icon-only
|
||||||
@click="
|
@click="
|
||||||
|
|
@ -547,6 +555,9 @@ watch(
|
||||||
v-model:contact-name="data.contactName"
|
v-model:contact-name="data.contactName"
|
||||||
v-model:email="data.contactEmail"
|
v-model:email="data.contactEmail"
|
||||||
v-model:contact-tel="data.contactTel"
|
v-model:contact-tel="data.contactTel"
|
||||||
|
v-model:attachment="attachment"
|
||||||
|
:attachment-list="attachmentList"
|
||||||
|
@delete-attachment="(name) => $emit('deleteAttachment', name)"
|
||||||
/>
|
/>
|
||||||
<AddressForm
|
<AddressForm
|
||||||
id="agencies-address-info"
|
id="agencies-address-info"
|
||||||
|
|
@ -597,6 +608,7 @@ watch(
|
||||||
v-model:on-create-data-list="imageListOnCreate"
|
v-model:on-create-data-list="imageListOnCreate"
|
||||||
v-model:image-url="imageState.imageUrl"
|
v-model:image-url="imageState.imageUrl"
|
||||||
v-model:data-list="imageList"
|
v-model:data-list="imageList"
|
||||||
|
:changeDisabled="hideAction"
|
||||||
:on-create="model"
|
:on-create="model"
|
||||||
:hiddenFooter="!imageState.isImageEdit"
|
:hiddenFooter="!imageState.isImageEdit"
|
||||||
@add-image="addImage"
|
@add-image="addImage"
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { Icon } from '@iconify/vue/dist/iconify.js';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
|
|
||||||
import { baseUrl } from 'src/stores/utils';
|
import { baseUrl, canAccess } from 'src/stores/utils';
|
||||||
import { useNavigator } from 'src/stores/navigator';
|
import { useNavigator } from 'src/stores/navigator';
|
||||||
import { useInstitution } from 'src/stores/institution';
|
import { useInstitution } from 'src/stores/institution';
|
||||||
import { Institution, InstitutionPayload } from 'src/stores/institution/types';
|
import { Institution, InstitutionPayload } from 'src/stores/institution/types';
|
||||||
|
|
@ -115,6 +115,8 @@ const blankFormData: InstitutionPayload = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const attachment = ref<File[]>([]);
|
||||||
|
const attachmentList = ref<{ name: string; url: string }[]>([]);
|
||||||
const statusFilter = ref<'all' | 'statusACTIVE' | 'statusINACTIVE'>('all');
|
const statusFilter = ref<'all' | 'statusACTIVE' | 'statusINACTIVE'>('all');
|
||||||
const refAgenciesDialog = ref();
|
const refAgenciesDialog = ref();
|
||||||
const formData = ref<InstitutionPayload>(structuredClone(blankFormData));
|
const formData = ref<InstitutionPayload>(structuredClone(blankFormData));
|
||||||
|
|
@ -145,6 +147,8 @@ function resetForm() {
|
||||||
pageState.addModal = false;
|
pageState.addModal = false;
|
||||||
pageState.viewDrawer = false;
|
pageState.viewDrawer = false;
|
||||||
currAgenciesData.value = undefined;
|
currAgenciesData.value = undefined;
|
||||||
|
attachment.value = [];
|
||||||
|
attachmentList.value = [];
|
||||||
formData.value = structuredClone(blankFormData);
|
formData.value = structuredClone(blankFormData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,7 +158,7 @@ function undo() {
|
||||||
pageState.isDrawerEdit = false;
|
pageState.isDrawerEdit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function assignFormData(data: Institution) {
|
async function assignFormData(data: Institution) {
|
||||||
currAgenciesData.value = data;
|
currAgenciesData.value = data;
|
||||||
formData.value = {
|
formData.value = {
|
||||||
group: data.group,
|
group: data.group,
|
||||||
|
|
@ -174,9 +178,9 @@ function assignFormData(data: Institution) {
|
||||||
provinceId: data.provinceId,
|
provinceId: data.provinceId,
|
||||||
selectedImage: data.selectedImage,
|
selectedImage: data.selectedImage,
|
||||||
status: data.status,
|
status: data.status,
|
||||||
contactEmail: data.contactEmail,
|
contactEmail: data.contactEmail || '',
|
||||||
contactName: data.contactName,
|
contactName: data.contactName || '',
|
||||||
contactTel: data.contactTel,
|
contactTel: data.contactTel || '',
|
||||||
bank: data.bank.map((v) => ({
|
bank: data.bank.map((v) => ({
|
||||||
bankName: v.bankName,
|
bankName: v.bankName,
|
||||||
accountNumber: v.accountNumber,
|
accountNumber: v.accountNumber,
|
||||||
|
|
@ -187,6 +191,8 @@ function assignFormData(data: Institution) {
|
||||||
bankUrl: `${baseUrl}/institution/${data.id}/bank-qr/${v.id}?ts=${Date.now()}`,
|
bankUrl: `${baseUrl}/institution/${data.id}/bank-qr/${v.id}?ts=${Date.now()}`,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
await fetchAttachment();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submit(opt?: { selectedImage: string }) {
|
async function submit(opt?: { selectedImage: string }) {
|
||||||
|
|
@ -214,7 +220,6 @@ async function submit(opt?: { selectedImage: string }) {
|
||||||
...v,
|
...v,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
console.log('payload', payload);
|
|
||||||
if (
|
if (
|
||||||
(pageState.isDrawerEdit && currAgenciesData.value?.id) ||
|
(pageState.isDrawerEdit && currAgenciesData.value?.id) ||
|
||||||
(opt?.selectedImage && currAgenciesData.value?.id)
|
(opt?.selectedImage && currAgenciesData.value?.id)
|
||||||
|
|
@ -229,18 +234,29 @@ async function submit(opt?: { selectedImage: string }) {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
attachment.value.forEach(async (file) => {
|
||||||
|
await institutionStore.putAttachment({
|
||||||
|
parentId: ret.id || '',
|
||||||
|
name: file.name,
|
||||||
|
file: file,
|
||||||
|
});
|
||||||
|
});
|
||||||
pageState.isDrawerEdit = false;
|
pageState.isDrawerEdit = false;
|
||||||
currAgenciesData.value = ret;
|
currAgenciesData.value = ret;
|
||||||
formData.value.selectedImage = ret.selectedImage;
|
formData.value.selectedImage = ret.selectedImage;
|
||||||
await fetchData($q.screen.xs);
|
await fetchData($q.screen.xs);
|
||||||
|
attachment.value = [];
|
||||||
|
|
||||||
if (refAgenciesDialog.value && opt?.selectedImage) {
|
if (refAgenciesDialog.value && opt?.selectedImage) {
|
||||||
refAgenciesDialog.value.clearImageState();
|
refAgenciesDialog.value.clearImageState();
|
||||||
}
|
}
|
||||||
|
setTimeout(async () => {
|
||||||
|
await fetchAttachment();
|
||||||
|
}, 300);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await institutionStore.createInstitution(
|
const res = await institutionStore.createInstitution(
|
||||||
{
|
{
|
||||||
...payload,
|
...payload,
|
||||||
code: formData.value.group || '',
|
code: formData.value.group || '',
|
||||||
|
|
@ -248,6 +264,16 @@ async function submit(opt?: { selectedImage: string }) {
|
||||||
imageListOnCreate.value,
|
imageListOnCreate.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!res) return;
|
||||||
|
|
||||||
|
attachment.value.forEach(async (file) => {
|
||||||
|
await institutionStore.putAttachment({
|
||||||
|
parentId: res.id || '',
|
||||||
|
name: file.name,
|
||||||
|
file: file,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
await fetchData($q.screen.xs);
|
await fetchData($q.screen.xs);
|
||||||
pageState.addModal = false;
|
pageState.addModal = false;
|
||||||
return;
|
return;
|
||||||
|
|
@ -347,6 +373,49 @@ async function changeStatus(id?: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function deleteAttachment(attachmentName: string) {
|
||||||
|
dialog({
|
||||||
|
color: 'negative',
|
||||||
|
icon: 'mdi-trash-can-outline',
|
||||||
|
title: t('dialog.title.confirmDelete', {
|
||||||
|
msg: t('personnel.form.attachment'),
|
||||||
|
}),
|
||||||
|
actionText: t('general.delete'),
|
||||||
|
persistent: true,
|
||||||
|
message: t('dialog.message.confirmDelete'),
|
||||||
|
action: async () => {
|
||||||
|
if (!currAgenciesData.value?.id) return;
|
||||||
|
institutionStore.delAttachment({
|
||||||
|
parentId: currAgenciesData.value?.id,
|
||||||
|
name: attachmentName,
|
||||||
|
});
|
||||||
|
setTimeout(async () => {
|
||||||
|
await fetchAttachment();
|
||||||
|
}, 300);
|
||||||
|
},
|
||||||
|
cancel: () => {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchAttachment() {
|
||||||
|
const resAttachment = await institutionStore.listAttachment({
|
||||||
|
parentId: currAgenciesData.value.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!resAttachment) return;
|
||||||
|
|
||||||
|
attachmentList.value = await Promise.all(
|
||||||
|
resAttachment.map(async (f) => ({
|
||||||
|
name: f,
|
||||||
|
url: await institutionStore.getAttachment({
|
||||||
|
parentId: currAgenciesData.value.id,
|
||||||
|
name: f,
|
||||||
|
download: false,
|
||||||
|
}),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
navigatorStore.current.title = 'agencies.title';
|
navigatorStore.current.title = 'agencies.title';
|
||||||
navigatorStore.current.path = [{ text: 'agencies.caption', i18n: true }];
|
navigatorStore.current.path = [{ text: 'agencies.caption', i18n: true }];
|
||||||
|
|
@ -366,6 +435,7 @@ watch(
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FloatingActionButton
|
<FloatingActionButton
|
||||||
|
v-if="canAccess('agencies', 'edit')"
|
||||||
style="z-index: 999"
|
style="z-index: 999"
|
||||||
hide-icon
|
hide-icon
|
||||||
@click="triggerDialog('add')"
|
@click="triggerDialog('add')"
|
||||||
|
|
@ -750,6 +820,7 @@ watch(
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<KebabAction
|
<KebabAction
|
||||||
|
v-if="canAccess('agencies', 'edit')"
|
||||||
:id-name="props.row.name"
|
:id-name="props.row.name"
|
||||||
:status="props.row.status"
|
:status="props.row.status"
|
||||||
@view="
|
@view="
|
||||||
|
|
@ -833,6 +904,7 @@ watch(
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<KebabAction
|
<KebabAction
|
||||||
|
v-if="canAccess('agencies', 'edit')"
|
||||||
:id-name="props.row.id"
|
:id-name="props.row.id"
|
||||||
:status="props.row.status"
|
:status="props.row.status"
|
||||||
@view="
|
@view="
|
||||||
|
|
@ -920,7 +992,10 @@ watch(
|
||||||
{{ $t('general.recordPerPage') }}
|
{{ $t('general.recordPerPage') }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<PaginationPageSize v-model="pageSize" />
|
<PaginationPageSize
|
||||||
|
v-model="pageSize"
|
||||||
|
:fetch-data="() => fetchData()"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -971,14 +1046,18 @@ watch(
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
@change-status="triggerChangeStatus"
|
@change-status="triggerChangeStatus"
|
||||||
|
@delete-attachment="deleteAttachment"
|
||||||
:readonly="!pageState.isDrawerEdit"
|
:readonly="!pageState.isDrawerEdit"
|
||||||
:isEdit="pageState.isDrawerEdit"
|
:isEdit="pageState.isDrawerEdit"
|
||||||
|
:hide-action="!canAccess('agencies', 'edit')"
|
||||||
v-model="pageState.addModal"
|
v-model="pageState.addModal"
|
||||||
v-model:drawer-model="pageState.viewDrawer"
|
v-model:drawer-model="pageState.viewDrawer"
|
||||||
v-model:data="formData"
|
v-model:data="formData"
|
||||||
v-model:form-bank-book="formData.bank"
|
v-model:form-bank-book="formData.bank"
|
||||||
v-model:image-list-on-create="imageListOnCreate"
|
v-model:image-list-on-create="imageListOnCreate"
|
||||||
v-model:deletes-status-qr-code-bank-imag="deletesStatusQrCodeBankImag"
|
v-model:deletes-status-qr-code-bank-imag="deletesStatusQrCodeBankImag"
|
||||||
|
v-model:attachment="attachment"
|
||||||
|
:attachment-list="attachmentList"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import {
|
||||||
EmployeePassportPayload,
|
EmployeePassportPayload,
|
||||||
EmployeeVisaPayload,
|
EmployeeVisaPayload,
|
||||||
} from 'stores/employee/types';
|
} from 'stores/employee/types';
|
||||||
|
import { canAccess } from 'src/stores/utils';
|
||||||
|
|
||||||
type Data = {
|
type Data = {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -50,6 +51,8 @@ defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const group = ref('passport');
|
const group = ref('passport');
|
||||||
|
const refFormEmployeePassport = ref();
|
||||||
|
const refFormEmployeeVisa = ref();
|
||||||
|
|
||||||
const requestListStore = useRequestList();
|
const requestListStore = useRequestList();
|
||||||
|
|
||||||
|
|
@ -58,6 +61,7 @@ const props = withDefaults(
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
listDocument: string[];
|
listDocument: string[];
|
||||||
currentId: { customer: string; employee: string };
|
currentId: { customer: string; employee: string };
|
||||||
|
prefix?: string;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
listDocument: () => [],
|
listDocument: () => [],
|
||||||
|
|
@ -241,14 +245,14 @@ function changeCustomerTab(opts: { tab: 'customer' | 'employee' }) {
|
||||||
<nav class="q-ml-auto row" v-if="!readonly">
|
<nav class="q-ml-auto row" v-if="!readonly">
|
||||||
<CancelButton
|
<CancelButton
|
||||||
v-if="state.isEdit"
|
v-if="state.isEdit"
|
||||||
id="btn-info-basic-undo"
|
:id="`btn-docs-${props.prefix || 'nome'}-info-basic-undo`"
|
||||||
icon-only
|
icon-only
|
||||||
type="button"
|
type="button"
|
||||||
@click.stop="triggerCancel"
|
@click.stop="triggerCancel"
|
||||||
/>
|
/>
|
||||||
<EditButton
|
<EditButton
|
||||||
v-if="!state.isEdit"
|
v-if="!state.isEdit"
|
||||||
id="btn-info-basic-edit"
|
:id="`btn-docs-${props.prefix || 'nome'}-info-basic-edit`"
|
||||||
icon-only
|
icon-only
|
||||||
@click.stop="triggerEdit"
|
@click.stop="triggerEdit"
|
||||||
type="button"
|
type="button"
|
||||||
|
|
@ -474,6 +478,13 @@ function changeCustomerTab(opts: { tab: 'customer' | 'employee' }) {
|
||||||
<q-td>
|
<q-td>
|
||||||
<span class="row justify-end no-wrap">
|
<span class="row justify-end no-wrap">
|
||||||
<OcrDialog
|
<OcrDialog
|
||||||
|
:disabled-submit="
|
||||||
|
group === 'passport'
|
||||||
|
? !refFormEmployeePassport
|
||||||
|
: group === 'visa'
|
||||||
|
? !refFormEmployeeVisa
|
||||||
|
: undefined
|
||||||
|
"
|
||||||
@submit="
|
@submit="
|
||||||
(file, meta) => {
|
(file, meta) => {
|
||||||
$emit(
|
$emit(
|
||||||
|
|
@ -500,7 +511,13 @@ function changeCustomerTab(opts: { tab: 'customer' | 'employee' }) {
|
||||||
>
|
>
|
||||||
<template #trigger="{ browse }">
|
<template #trigger="{ browse }">
|
||||||
<MainButton
|
<MainButton
|
||||||
v-if="!!state.isEdit"
|
v-if="
|
||||||
|
!!state.isEdit &&
|
||||||
|
(props.row.documentType === 'passport' ||
|
||||||
|
props.row.documentType === 'visa'
|
||||||
|
? canAccess('customer', 'edit')
|
||||||
|
: true)
|
||||||
|
"
|
||||||
iconOnly
|
iconOnly
|
||||||
icon="mdi-tray-arrow-up"
|
icon="mdi-tray-arrow-up"
|
||||||
color="var(--positive-bg)"
|
color="var(--positive-bg)"
|
||||||
|
|
@ -513,6 +530,7 @@ function changeCustomerTab(opts: { tab: 'customer' | 'employee' }) {
|
||||||
</template>
|
</template>
|
||||||
<template #body="{ metadata, isRunning }">
|
<template #body="{ metadata, isRunning }">
|
||||||
<FormEmployeePassport
|
<FormEmployeePassport
|
||||||
|
ref="refFormEmployeePassport"
|
||||||
v-if="group === 'passport' && metadata"
|
v-if="group === 'passport' && metadata"
|
||||||
:title="$t('customerEmployee.form.group.passport')"
|
:title="$t('customerEmployee.form.group.passport')"
|
||||||
dense
|
dense
|
||||||
|
|
@ -545,6 +563,7 @@ function changeCustomerTab(opts: { tab: 'customer' | 'employee' }) {
|
||||||
|
|
||||||
<FormEmployeeVisa
|
<FormEmployeeVisa
|
||||||
v-if="group === 'visa' && metadata"
|
v-if="group === 'visa' && metadata"
|
||||||
|
ref="refFormEmployeeVisa"
|
||||||
:title="$t('customerEmployee.form.group.visa')"
|
:title="$t('customerEmployee.form.group.visa')"
|
||||||
ocr
|
ocr
|
||||||
dense
|
dense
|
||||||
|
|
@ -564,6 +583,7 @@ function changeCustomerTab(opts: { tab: 'customer' | 'employee' }) {
|
||||||
v-model:remark="metadata.remark"
|
v-model:remark="metadata.remark"
|
||||||
v-model:worker-type="metadata.workerType"
|
v-model:worker-type="metadata.workerType"
|
||||||
v-model:visa-number="metadata.doc_number"
|
v-model:visa-number="metadata.doc_number"
|
||||||
|
v-model:report-date="metadata.reportDate"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-if="isRunning"
|
v-if="isRunning"
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import { useRequestList } from 'src/stores/request-list';
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
step: Step;
|
step: Step;
|
||||||
|
prefix?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const requestListStore = useRequestList();
|
const requestListStore = useRequestList();
|
||||||
|
|
@ -100,21 +101,21 @@ function assignToForm() {
|
||||||
<nav class="q-ml-auto row" v-if="!readonly">
|
<nav class="q-ml-auto row" v-if="!readonly">
|
||||||
<UndoButton
|
<UndoButton
|
||||||
v-if="state.isEdit"
|
v-if="state.isEdit"
|
||||||
id="btn-info-basic-undo"
|
:id="`btn-duty-${props.prefix || 'nome'}-info-basic-undo`"
|
||||||
icon-only
|
icon-only
|
||||||
type="button"
|
type="button"
|
||||||
@click.stop="triggerUndo"
|
@click.stop="triggerUndo"
|
||||||
/>
|
/>
|
||||||
<SaveButton
|
<SaveButton
|
||||||
v-if="state.isEdit"
|
v-if="state.isEdit"
|
||||||
id="btn-info-basic-save"
|
:id="`btn-duty-${props.prefix || 'nome'}-info-basic-save`"
|
||||||
icon-only
|
icon-only
|
||||||
type="submit"
|
type="submit"
|
||||||
@click.stop="triggerSubmit"
|
@click.stop="triggerSubmit"
|
||||||
/>
|
/>
|
||||||
<EditButton
|
<EditButton
|
||||||
v-if="!state.isEdit"
|
v-if="!state.isEdit"
|
||||||
id="btn-info-basic-edit"
|
:id="`btn-duty-${props.prefix || 'nome'}-info-basic-edit`"
|
||||||
icon-only
|
icon-only
|
||||||
@click.stop="triggerEdit"
|
@click.stop="triggerEdit"
|
||||||
type="button"
|
type="button"
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ const props = defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
step: Step;
|
step: Step;
|
||||||
requestWorkId: string;
|
requestWorkId: string;
|
||||||
|
prefix?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const requestListStore = useRequestList();
|
const requestListStore = useRequestList();
|
||||||
|
|
@ -90,21 +91,21 @@ function assignToForm() {
|
||||||
<nav class="q-ml-auto row" v-if="!readonly">
|
<nav class="q-ml-auto row" v-if="!readonly">
|
||||||
<UndoButton
|
<UndoButton
|
||||||
v-if="state.isEdit"
|
v-if="state.isEdit"
|
||||||
id="btn-info-basic-undo"
|
:id="`btn-form-${props.prefix || 'nome'}-info-basic-undo`"
|
||||||
icon-only
|
icon-only
|
||||||
type="button"
|
type="button"
|
||||||
@click.stop="triggerUndo"
|
@click.stop="triggerUndo"
|
||||||
/>
|
/>
|
||||||
<SaveButton
|
<SaveButton
|
||||||
v-if="state.isEdit"
|
v-if="state.isEdit"
|
||||||
id="btn-info-basic-save"
|
:id="`btn-form-${props.prefix || 'nome'}-info-basic-save`"
|
||||||
icon-only
|
icon-only
|
||||||
type="submit"
|
type="submit"
|
||||||
@click.stop="triggerSubmit"
|
@click.stop="triggerSubmit"
|
||||||
/>
|
/>
|
||||||
<EditButton
|
<EditButton
|
||||||
v-if="!state.isEdit"
|
v-if="!state.isEdit"
|
||||||
id="btn-info-basic-edit"
|
:id="`btn-form-${props.prefix || 'nome'}-info-basic-edit`"
|
||||||
icon-only
|
icon-only
|
||||||
@click.stop="triggerEdit"
|
@click.stop="triggerEdit"
|
||||||
type="button"
|
type="button"
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ const responsibleUserId = defineModel<string>('responsibleUserId', {
|
||||||
defineProps<{
|
defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
districtId?: string;
|
districtId?: string;
|
||||||
|
prefix?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
watch(responsibleUserLocal, (lhs, rhs) => {
|
watch(responsibleUserLocal, (lhs, rhs) => {
|
||||||
|
|
@ -27,6 +28,8 @@ watch(responsibleUserLocal, (lhs, rhs) => {
|
||||||
:label="$t('requestList.localEmployee')"
|
:label="$t('requestList.localEmployee')"
|
||||||
:disable="readonly"
|
:disable="readonly"
|
||||||
class="col"
|
class="col"
|
||||||
|
:id="`${prefix || 'nome'}-radio-local-employee`"
|
||||||
|
:for="`${prefix || 'nome'}-radio-local-employee`"
|
||||||
/>
|
/>
|
||||||
<q-radio
|
<q-radio
|
||||||
v-model="responsibleUserLocal"
|
v-model="responsibleUserLocal"
|
||||||
|
|
@ -34,6 +37,8 @@ watch(responsibleUserLocal, (lhs, rhs) => {
|
||||||
:label="$t('requestList.nonLocalEmployee')"
|
:label="$t('requestList.nonLocalEmployee')"
|
||||||
:disable="readonly"
|
:disable="readonly"
|
||||||
class="col"
|
class="col"
|
||||||
|
:id="`${prefix || 'nome'}-radio-non-local-employee`"
|
||||||
|
:for="`${prefix || 'nome'}-radio-non-local-employee`"
|
||||||
/>
|
/>
|
||||||
<div class="col" />
|
<div class="col" />
|
||||||
<div class="offset-md-7"></div>
|
<div class="offset-md-7"></div>
|
||||||
|
|
@ -52,6 +57,8 @@ watch(responsibleUserLocal, (lhs, rhs) => {
|
||||||
}"
|
}"
|
||||||
:readonly
|
:readonly
|
||||||
:label="$t('general.select', { msg: $t('personnel.MESSENGER') })"
|
:label="$t('general.select', { msg: $t('personnel.MESSENGER') })"
|
||||||
|
:id="`${prefix || 'nome'}-select-user`"
|
||||||
|
:for="`${prefix || 'nome'}-select-user`"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import { column } from './constants';
|
||||||
import useFlowStore from 'src/stores/flow';
|
import useFlowStore from 'src/stores/flow';
|
||||||
import { useRequestList } from 'src/stores/request-list';
|
import { useRequestList } from 'src/stores/request-list';
|
||||||
import { RequestData, RequestDataStatus } from 'src/stores/request-list/types';
|
import { RequestData, RequestDataStatus } from 'src/stores/request-list/types';
|
||||||
import { dialogWarningClose } from 'src/stores/utils';
|
import { dialogWarningClose, canAccess } from 'src/stores/utils';
|
||||||
import { CancelButton, SaveButton } from 'src/components/button';
|
import { CancelButton, SaveButton } from 'src/components/button';
|
||||||
import { getRole } from 'src/services/keycloak';
|
import { getRole } from 'src/services/keycloak';
|
||||||
import FloatingActionButton from 'src/components/FloatingActionButton.vue';
|
import FloatingActionButton from 'src/components/FloatingActionButton.vue';
|
||||||
|
|
@ -95,24 +95,12 @@ function triggerCancel(id: string) {
|
||||||
const res = await requestListStore.cancelRequest(id);
|
const res = await requestListStore.cancelRequest(id);
|
||||||
if (res) {
|
if (res) {
|
||||||
fetchList();
|
fetchList();
|
||||||
|
fetchStats();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const hideAction = computed(() => {
|
|
||||||
const role = getRole();
|
|
||||||
const allowedRoles = [
|
|
||||||
'head_of_admin',
|
|
||||||
'head_of_sale',
|
|
||||||
'admin',
|
|
||||||
'sale',
|
|
||||||
'system',
|
|
||||||
];
|
|
||||||
|
|
||||||
return !role || !role.some((r) => allowedRoles.includes(r));
|
|
||||||
});
|
|
||||||
|
|
||||||
function triggerView(opts: { requestData: RequestData }) {
|
function triggerView(opts: { requestData: RequestData }) {
|
||||||
const url = new URL(
|
const url = new URL(
|
||||||
`/request-list/${opts.requestData.id}`,
|
`/request-list/${opts.requestData.id}`,
|
||||||
|
|
@ -473,11 +461,12 @@ watch(
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<TableRequestList
|
<TableRequestList
|
||||||
|
:no-link="!canAccess('customer', 'view')"
|
||||||
:columns="column"
|
:columns="column"
|
||||||
:rows="data"
|
:rows="data"
|
||||||
:grid="pageState.gridView"
|
:grid="pageState.gridView"
|
||||||
:visible-columns="pageState.fieldSelected"
|
:visible-columns="pageState.fieldSelected"
|
||||||
:hide-action
|
:hide-action="!canAccess('requestList', 'edit')"
|
||||||
@view="(data) => triggerView({ requestData: data })"
|
@view="(data) => triggerView({ requestData: data })"
|
||||||
@delete="(data) => triggerCancel(data.id)"
|
@delete="(data) => triggerCancel(data.id)"
|
||||||
@reject-cancel="
|
@reject-cancel="
|
||||||
|
|
@ -574,6 +563,7 @@ watch(
|
||||||
v-if="requestListActionData"
|
v-if="requestListActionData"
|
||||||
v-model="pageState.requestListActionDialog"
|
v-model="pageState.requestListActionDialog"
|
||||||
:request-list="requestListActionData"
|
:request-list="requestListActionData"
|
||||||
|
:no-link="!canAccess('customer', 'view')"
|
||||||
@submit="submitRequestListAction"
|
@submit="submitRequestListAction"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ const props = defineProps<{
|
||||||
step: Step;
|
step: Step;
|
||||||
responsibleAreaDistrictId?: string;
|
responsibleAreaDistrictId?: string;
|
||||||
defaultMessenger?: string;
|
defaultMessenger?: string;
|
||||||
|
prefix?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
|
@ -57,6 +58,7 @@ const formData = ref<AttributesForm>(defaultForm);
|
||||||
function triggerUndo() {
|
function triggerUndo() {
|
||||||
assignToForm();
|
assignToForm();
|
||||||
state.isEdit = false;
|
state.isEdit = false;
|
||||||
|
refForm.value?.resetValidation();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function triggerSubmit() {
|
async function triggerSubmit() {
|
||||||
|
|
@ -85,7 +87,11 @@ function assignToForm() {
|
||||||
customerDutyCost: attributesForm.value.customerDutyCost ?? 30,
|
customerDutyCost: attributesForm.value.customerDutyCost ?? 30,
|
||||||
companyDuty: attributesForm.value.companyDuty ?? false,
|
companyDuty: attributesForm.value.companyDuty ?? false,
|
||||||
companyDutyCost: attributesForm.value.companyDutyCost ?? 30,
|
companyDutyCost: attributesForm.value.companyDutyCost ?? 30,
|
||||||
responsibleUserLocal: attributesForm.value.responsibleUserLocal ?? true,
|
responsibleUserLocal: attributesForm.value.responsibleUserLocal
|
||||||
|
? attributesForm.value.responsibleUserLocal
|
||||||
|
: props.responsibleAreaDistrictId
|
||||||
|
? false
|
||||||
|
: true,
|
||||||
responsibleUserId:
|
responsibleUserId:
|
||||||
attributesForm.value.responsibleUserId || props.defaultMessenger,
|
attributesForm.value.responsibleUserId || props.defaultMessenger,
|
||||||
individualDuty: attributesForm.value.individualDuty ?? false,
|
individualDuty: attributesForm.value.individualDuty ?? false,
|
||||||
|
|
@ -111,21 +117,21 @@ function assignToForm() {
|
||||||
<nav class="q-ml-auto row" v-if="!readonly">
|
<nav class="q-ml-auto row" v-if="!readonly">
|
||||||
<UndoButton
|
<UndoButton
|
||||||
v-if="state.isEdit"
|
v-if="state.isEdit"
|
||||||
id="btn-info-basic-undo"
|
:id="`btn-messenger-${props.prefix || 'nome'}-info-basic-undo`"
|
||||||
icon-only
|
icon-only
|
||||||
type="button"
|
type="button"
|
||||||
@click.stop="triggerUndo"
|
@click.stop="triggerUndo"
|
||||||
/>
|
/>
|
||||||
<SaveButton
|
<SaveButton
|
||||||
v-if="state.isEdit"
|
v-if="state.isEdit"
|
||||||
id="btn-info-basic-save"
|
:id="`btn-messenger-${props.prefix || 'nome'}-info-basic-save`"
|
||||||
icon-only
|
icon-only
|
||||||
type="submit"
|
type="submit"
|
||||||
@click.stop="(e) => refForm?.submit(e)"
|
@click.stop="(e) => refForm?.submit(e)"
|
||||||
/>
|
/>
|
||||||
<EditButton
|
<EditButton
|
||||||
v-if="!state.isEdit"
|
v-if="!state.isEdit"
|
||||||
id="btn-info-basic-edit"
|
:id="`btn-messenger-${props.prefix || 'nome'}-info-basic-edit`"
|
||||||
icon-only
|
icon-only
|
||||||
@click.stop="triggerEdit"
|
@click.stop="triggerEdit"
|
||||||
type="button"
|
type="button"
|
||||||
|
|
@ -152,6 +158,7 @@ function assignToForm() {
|
||||||
v-model:responsible-user-local="formData.responsibleUserLocal"
|
v-model:responsible-user-local="formData.responsibleUserLocal"
|
||||||
v-model:responsible-user-id="formData.responsibleUserId"
|
v-model:responsible-user-id="formData.responsibleUserId"
|
||||||
:district-id="responsibleAreaDistrictId"
|
:district-id="responsibleAreaDistrictId"
|
||||||
|
:prefix
|
||||||
/>
|
/>
|
||||||
</q-form>
|
</q-form>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@ function changeableStatus(currentStatus?: RequestWorkStatus) {
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<q-expansion-item
|
<q-expansion-item
|
||||||
|
:id="`expansion-${product?.name || name}`"
|
||||||
|
:for="`expansion-${product?.name || name}`"
|
||||||
dense
|
dense
|
||||||
:class="{ 'status-unpaid': !paySuccess }"
|
:class="{ 'status-unpaid': !paySuccess }"
|
||||||
class="overflow-hidden"
|
class="overflow-hidden"
|
||||||
|
|
@ -146,6 +148,8 @@ function changeableStatus(currentStatus?: RequestWorkStatus) {
|
||||||
<div class="q-ml-auto q-gutter-y-xs">
|
<div class="q-ml-auto q-gutter-y-xs">
|
||||||
<div class="justify-end flex">
|
<div class="justify-end flex">
|
||||||
<q-btn-dropdown
|
<q-btn-dropdown
|
||||||
|
:id="`btn-dropdown-${product?.name || name}`"
|
||||||
|
:for="`btn-dropdown-${product?.name || name}`"
|
||||||
:disable="
|
:disable="
|
||||||
readonly || changeableStatus(status?.workStatus).length === 0
|
readonly || changeableStatus(status?.workStatus).length === 0
|
||||||
"
|
"
|
||||||
|
|
@ -197,6 +201,8 @@ function changeableStatus(currentStatus?: RequestWorkStatus) {
|
||||||
<q-list dense>
|
<q-list dense>
|
||||||
<q-item
|
<q-item
|
||||||
v-for="(value, index) in changeableStatus(status?.workStatus)"
|
v-for="(value, index) in changeableStatus(status?.workStatus)"
|
||||||
|
:id="`btn-dropdown-${product?.name || name}-${value}`"
|
||||||
|
:for="`btn-dropdown-${product?.name || name}-${value}`"
|
||||||
:key="index"
|
:key="index"
|
||||||
clickable
|
clickable
|
||||||
v-close-popup
|
v-close-popup
|
||||||
|
|
@ -271,15 +277,15 @@ function changeableStatus(currentStatus?: RequestWorkStatus) {
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(
|
:deep(
|
||||||
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
|
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
|
||||||
) {
|
) {
|
||||||
color: var(--brand-1);
|
color: var(--brand-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(
|
:deep(
|
||||||
.q-item.q-item-type.row.no-wrap.q-item--dense.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable.surface-1
|
.q-item.q-item-type.row.no-wrap.q-item--dense.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable.surface-1
|
||||||
.q-focus-helper
|
.q-focus-helper
|
||||||
) {
|
) {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ const props = withDefaults(
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
propertiesToShow: (PropString | PropNumber | PropDate | PropOptions)[];
|
propertiesToShow: (PropString | PropNumber | PropDate | PropOptions)[];
|
||||||
requestListData: RequestData;
|
requestListData: RequestData;
|
||||||
|
prefix?: string;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
|
|
@ -128,7 +129,7 @@ defineEmits<{
|
||||||
<nav class="q-ml-auto row" v-if="!readonly">
|
<nav class="q-ml-auto row" v-if="!readonly">
|
||||||
<UndoButton
|
<UndoButton
|
||||||
v-if="state.isEdit"
|
v-if="state.isEdit"
|
||||||
id="btn-info-basic-undo"
|
:id="`btn-properties-${props.prefix || 'nome'}-info-basic-undo`"
|
||||||
icon-only
|
icon-only
|
||||||
type="button"
|
type="button"
|
||||||
@click.stop="triggerUndo"
|
@click.stop="triggerUndo"
|
||||||
|
|
@ -136,13 +137,14 @@ defineEmits<{
|
||||||
<SaveButton
|
<SaveButton
|
||||||
v-if="state.isEdit"
|
v-if="state.isEdit"
|
||||||
id="btn-info-basic-save"
|
id="btn-info-basic-save"
|
||||||
|
:id="`btn-properties-${props.prefix || 'nome'}-info-basic-save`"
|
||||||
icon-only
|
icon-only
|
||||||
type="submit"
|
type="submit"
|
||||||
@click.stop="triggerSubmit"
|
@click.stop="triggerSubmit"
|
||||||
/>
|
/>
|
||||||
<EditButton
|
<EditButton
|
||||||
v-if="!state.isEdit"
|
v-if="!state.isEdit"
|
||||||
id="btn-info-basic-edit"
|
:id="`btn-properties-${props.prefix || 'nome'}-info-basic-edit`"
|
||||||
icon-only
|
icon-only
|
||||||
@click.stop="triggerEdit"
|
@click.stop="triggerEdit"
|
||||||
type="button"
|
type="button"
|
||||||
|
|
|
||||||