Merge branch 'feat/ocr' into develop
This commit is contained in:
commit
7a56f205ec
19 changed files with 1452 additions and 495 deletions
|
|
@ -32,6 +32,7 @@ defineProps<{
|
|||
outlined?: boolean;
|
||||
readonly?: boolean;
|
||||
separator?: boolean;
|
||||
ocr?: boolean;
|
||||
|
||||
prefixId: string;
|
||||
}>();
|
||||
|
|
@ -84,7 +85,35 @@ watch(
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="row col-12">
|
||||
<div class="row col-12" v-if="ocr">
|
||||
<div class="col-12 row">
|
||||
<div class="col-6 flex flex-center">
|
||||
<q-img
|
||||
src="/images/customer-CORP-avartar.png "
|
||||
style="height: 100px; max-width: 50%"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-6 column">
|
||||
<q-input
|
||||
lazy-rules="ondemand"
|
||||
:for="`${prefixId}-input-passport-no`"
|
||||
:dense="dense"
|
||||
outlined
|
||||
:readonly="readonly"
|
||||
hide-bottom-space
|
||||
class="col-md-3 col-6"
|
||||
:label="$t('customerEmployee.form.passportNo')"
|
||||
v-model="passportNumber"
|
||||
:rules="[
|
||||
(val: string) =>
|
||||
!!val || $t('inputValidate') + $t('formDialogInputPassportNo'),
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row col-12" v-else>
|
||||
<div class="col-12 q-pb-sm text-weight-bold text-body1">
|
||||
<q-icon
|
||||
flat
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
import AppBox from './app/AppBox.vue';
|
||||
import { CancelButton, SaveButton } from './button';
|
||||
import { CancelButton, ClearButton, SaveButton } from './button';
|
||||
|
||||
defineExpose({ browse });
|
||||
defineProps<{
|
||||
|
|
@ -131,20 +131,15 @@ async function downloadImage(url: string) {
|
|||
class="row items-center justify-end q-py-sm q-px-md bordered-t"
|
||||
v-if="!hiddenFooter"
|
||||
>
|
||||
<q-btn
|
||||
dense
|
||||
unelevated
|
||||
flat
|
||||
:color="$q.dark.isActive ? 'grey-9' : 'grey-4'"
|
||||
:text-color="$q.dark.isActive ? 'grey-1' : 'grey-10'"
|
||||
:label="$t('general.clear')"
|
||||
<ClearButton
|
||||
outlined
|
||||
@click="
|
||||
inputFile && (inputFile.value = ''),
|
||||
(imageUrl = defaultUrl || fallbackUrl || ''),
|
||||
(file = null)
|
||||
"
|
||||
class="q-px-md q-mr-auto"
|
||||
:disable="
|
||||
:disabled="
|
||||
clearButtonDisabled ||
|
||||
imageUrl === fallbackUrl ||
|
||||
imageUrl === defaultUrl ||
|
||||
|
|
|
|||
26
src/components/button/ClearButton.vue
Normal file
26
src/components/button/ClearButton.vue
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<script lang="ts" setup>
|
||||
import MainButton from './MainButton.vue';
|
||||
|
||||
defineEmits<{
|
||||
(e: 'click', v: MouseEvent): void;
|
||||
}>();
|
||||
defineProps<{
|
||||
iconOnly?: boolean;
|
||||
solid?: boolean;
|
||||
outlined?: boolean;
|
||||
disabled?: boolean;
|
||||
dark?: boolean;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<MainButton
|
||||
@click="(e) => $emit('click', e)"
|
||||
v-bind="{ ...$props, ...$attrs }"
|
||||
icon="mdi-broom"
|
||||
color="var(--gray-7-hsl)"
|
||||
:title="iconOnly ? $t('general.clear') : undefined"
|
||||
>
|
||||
{{ $t('general.clear') }}
|
||||
</MainButton>
|
||||
</template>
|
||||
26
src/components/button/CloseButton.vue
Normal file
26
src/components/button/CloseButton.vue
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<script lang="ts" setup>
|
||||
import MainButton from './MainButton.vue';
|
||||
|
||||
defineEmits<{
|
||||
(e: 'click', v: MouseEvent): void;
|
||||
}>();
|
||||
defineProps<{
|
||||
iconOnly?: boolean;
|
||||
solid?: boolean;
|
||||
outlined?: boolean;
|
||||
disabled?: boolean;
|
||||
dark?: boolean;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<MainButton
|
||||
@click="(e) => $emit('click', e)"
|
||||
v-bind="{ ...$props, ...$attrs }"
|
||||
icon="mdi-close"
|
||||
color="var(--gray-7-hsl)"
|
||||
:title="iconOnly ? $t('general.clear') : undefined"
|
||||
>
|
||||
{{ $t('general.clear') }}
|
||||
</MainButton>
|
||||
</template>
|
||||
|
|
@ -6,3 +6,5 @@ export { default as DeleteButton } from './DeleteButton.vue';
|
|||
export { default as BackButton } from './BackButton.vue';
|
||||
export { default as UndoButton } from './UndoButton.vue';
|
||||
export { default as ToggleButton } from './ToggleButton.vue';
|
||||
export { default as ClearButton } from './ClearButton.vue';
|
||||
export { default as CloseButton } from './CloseButton.vue';
|
||||
|
|
|
|||
367
src/components/upload-file/FormCitizen.vue
Normal file
367
src/components/upload-file/FormCitizen.vue
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { QSelect } from 'quasar';
|
||||
import { selectFilterOptionRefMod } from 'stores/utils';
|
||||
import { getRole } from 'src/services/keycloak';
|
||||
import useOptionStore from 'stores/options';
|
||||
import { onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import DatePicker from '../shared/DatePicker.vue';
|
||||
const { locale } = useI18n();
|
||||
|
||||
import {
|
||||
dateFormat,
|
||||
calculateAge,
|
||||
parseAndFormatDate,
|
||||
disabledAfterToday,
|
||||
} from 'src/utils/datetime';
|
||||
|
||||
import {
|
||||
SaveButton,
|
||||
EditButton,
|
||||
DeleteButton,
|
||||
UndoButton,
|
||||
} from 'components/button';
|
||||
defineProps<{
|
||||
prefixId?: string;
|
||||
outlined?: boolean;
|
||||
readonly?: boolean;
|
||||
create?: boolean;
|
||||
actionDisabled?: boolean;
|
||||
customerType?: 'CORP' | 'PERS';
|
||||
orc?: boolean;
|
||||
}>();
|
||||
defineEmits<{
|
||||
(e: 'save'): void;
|
||||
(e: 'edit'): void;
|
||||
(e: 'delete'): void;
|
||||
(e: 'cancel'): void;
|
||||
}>();
|
||||
|
||||
const optionStore = useOptionStore();
|
||||
const namePrefix = defineModel<string | null>('namePrefix');
|
||||
const birthDate = defineModel<Date | string | null>('birthDate');
|
||||
const gender = defineModel<string>('gender');
|
||||
|
||||
const address = defineModel<string>('address');
|
||||
const firstName = defineModel<string>('firstName', { required: true });
|
||||
const lastName = defineModel<string>('lastName', { required: true });
|
||||
const firstNameEN = defineModel<string>('firstNameEn', { required: true });
|
||||
const lastNameEN = defineModel<string>('lastNameEn', { required: true });
|
||||
|
||||
const citizenId = defineModel<string | undefined>('citizenId', {
|
||||
required: true,
|
||||
});
|
||||
const nationality = defineModel<string>('nationality');
|
||||
|
||||
const religion = defineModel<string>('religion');
|
||||
|
||||
const branchOptions = defineModel<{ id: string; name: string }[]>(
|
||||
'branchOptions',
|
||||
{ default: [] },
|
||||
);
|
||||
const filteredBranchOptions = ref<Record<string, unknown>[]>([]);
|
||||
|
||||
let branchFilter: (
|
||||
value: string,
|
||||
update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
|
||||
) => void;
|
||||
|
||||
onMounted(() => {
|
||||
branchFilter = selectFilterOptionRefMod(
|
||||
branchOptions,
|
||||
filteredBranchOptions,
|
||||
'name',
|
||||
);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => branchOptions.value,
|
||||
() => {
|
||||
branchFilter = selectFilterOptionRefMod(
|
||||
branchOptions,
|
||||
filteredBranchOptions,
|
||||
'name',
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
const prefixNameOptions = ref<Record<string, unknown>[]>([]);
|
||||
let prefixNameFilter: (
|
||||
value: string,
|
||||
update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
|
||||
) => void;
|
||||
|
||||
const prefixNameEnOptions = ref<Record<string, unknown>[]>([]);
|
||||
let prefixNameEnFilter: (
|
||||
value: string,
|
||||
update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
|
||||
) => void;
|
||||
|
||||
const genderOptions = ref<Record<string, unknown>[]>([]);
|
||||
let genderFilter: (
|
||||
value: string,
|
||||
update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
|
||||
) => void;
|
||||
|
||||
onMounted(() => {
|
||||
prefixNameFilter = selectFilterOptionRefMod(
|
||||
ref(optionStore.globalOption?.prefix),
|
||||
prefixNameOptions,
|
||||
'label',
|
||||
);
|
||||
genderFilter = selectFilterOptionRefMod(
|
||||
ref(optionStore.globalOption?.gender),
|
||||
genderOptions,
|
||||
'label',
|
||||
);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => optionStore.globalOption,
|
||||
() => {
|
||||
prefixNameFilter = selectFilterOptionRefMod(
|
||||
ref(optionStore.globalOption.prefix),
|
||||
prefixNameOptions,
|
||||
'label',
|
||||
);
|
||||
genderFilter = selectFilterOptionRefMod(
|
||||
ref(optionStore.globalOption.gender),
|
||||
genderOptions,
|
||||
'label',
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
function formatCode(input: string | undefined, type: 'code' | 'number') {
|
||||
if (!input) return;
|
||||
return input.slice(...(type === 'code' ? [0, -6] : [-6]));
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="row q-mb-sm">
|
||||
<template v-if="orc">
|
||||
<div class="row" style="gap: 10px">
|
||||
<div class="col-4 flex flex-center">
|
||||
<q-img
|
||||
src="/images/customer-CORP-avartar.png"
|
||||
width="80px"
|
||||
height="80px"
|
||||
></q-img>
|
||||
</div>
|
||||
<div class="col row" style="gap: 10px">
|
||||
<q-input
|
||||
lazy-rules="ondemand"
|
||||
dense
|
||||
outlined
|
||||
:readonly="readonly"
|
||||
hide-bottom-space
|
||||
class="col-12"
|
||||
:label="$t('customer.form.citizenId')"
|
||||
for="input-citizen-id"
|
||||
v-model="citizenId"
|
||||
/>
|
||||
|
||||
<DatePicker
|
||||
:label="$t('form.birthDate')"
|
||||
v-model="birthDate"
|
||||
class="col-12"
|
||||
:id="`${prefixId}-input-birth-date`"
|
||||
:readonly="readonly"
|
||||
clearable
|
||||
/>
|
||||
|
||||
<q-input
|
||||
lazy-rules="ondemand"
|
||||
dense
|
||||
outlined
|
||||
:readonly="readonly"
|
||||
hide-bottom-space
|
||||
class="col"
|
||||
:label="$t('general.nationality')"
|
||||
for="input-nationality"
|
||||
v-model="nationality"
|
||||
/>
|
||||
|
||||
<q-input
|
||||
lazy-rules="ondemand"
|
||||
dense
|
||||
outlined
|
||||
:readonly="readonly"
|
||||
hide-bottom-space
|
||||
class="col"
|
||||
:label="$t('customer.form.religion')"
|
||||
for="input-religion"
|
||||
v-model="religion"
|
||||
/>
|
||||
|
||||
<q-select
|
||||
outlined
|
||||
use-input
|
||||
fill-input
|
||||
emit-value
|
||||
map-options
|
||||
hide-selected
|
||||
hide-bottom-space
|
||||
input-debounce="0"
|
||||
option-label="label"
|
||||
option-value="value"
|
||||
lazy-rules="ondemand"
|
||||
class="col"
|
||||
dense
|
||||
:readonly="readonly"
|
||||
:options="genderOptions"
|
||||
:hide-dropdown-icon="readonly"
|
||||
:for="`${prefixId}-select-gender`"
|
||||
:label="$t('form.gender')"
|
||||
@filter="genderFilter"
|
||||
:model-value="readonly ? gender || '-' : gender"
|
||||
@update:model-value="
|
||||
(v) => (typeof v === 'string' ? (gender = v) : '')
|
||||
"
|
||||
@clear="gender = ''"
|
||||
>
|
||||
<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 class="row q-col-gutter-sm">
|
||||
<q-select
|
||||
outlined
|
||||
use-input
|
||||
fill-input
|
||||
emit-value
|
||||
map-options
|
||||
hide-selected
|
||||
hide-bottom-space
|
||||
input-debounce="0"
|
||||
option-label="label"
|
||||
option-value="value"
|
||||
lazy-rules="ondemand"
|
||||
hide-dropdown-icon
|
||||
class="col-2"
|
||||
dense
|
||||
:readonly="readonly"
|
||||
:options="prefixNameOptions"
|
||||
:for="`${prefixId}-select-prefix-name`"
|
||||
:label="$t('form.prefixName')"
|
||||
@filter="prefixNameFilter"
|
||||
:model-value="readonly ? namePrefix || '-' : namePrefix"
|
||||
@update:model-value="
|
||||
(v) => {
|
||||
typeof v === 'string' ? (namePrefix = v) : '';
|
||||
}
|
||||
"
|
||||
@clear="namePrefix = ''"
|
||||
>
|
||||
<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-input
|
||||
lazy-rules="ondemand"
|
||||
dense
|
||||
outlined
|
||||
:readonly="readonly"
|
||||
hide-bottom-space
|
||||
class="col-5"
|
||||
:label="$t('customer.form.firstName')"
|
||||
for="input-first-name"
|
||||
v-model="firstName"
|
||||
/>
|
||||
|
||||
<q-input
|
||||
lazy-rules="ondemand"
|
||||
dense
|
||||
outlined
|
||||
:readonly="readonly"
|
||||
hide-bottom-space
|
||||
class="col-5"
|
||||
:label="$t('customer.form.lastName')"
|
||||
for="input-last-name"
|
||||
v-model="lastName"
|
||||
/>
|
||||
|
||||
<q-input
|
||||
lazy-rules="ondemand"
|
||||
dense
|
||||
outlined
|
||||
:disable="!readonly"
|
||||
:readonly="readonly"
|
||||
hide-bottom-space
|
||||
class="col-2"
|
||||
:label="$t('customer.form.prefixName')"
|
||||
for="input-prefix-name"
|
||||
:model-value="
|
||||
namePrefix ? $t(`customer.form.prefix.${namePrefix}`) : '-'
|
||||
"
|
||||
/>
|
||||
|
||||
<q-input
|
||||
lazy-rules="ondemand"
|
||||
dense
|
||||
outlined
|
||||
:readonly="readonly"
|
||||
hide-bottom-space
|
||||
class="col-5"
|
||||
:label="$t('customer.form.firstNameEN')"
|
||||
for="input-first-name-en"
|
||||
v-model="firstNameEN"
|
||||
/>
|
||||
<q-input
|
||||
lazy-rules="ondemand"
|
||||
dense
|
||||
outlined
|
||||
:readonly="readonly"
|
||||
hide-bottom-space
|
||||
class="col-5"
|
||||
:label="$t('customer.form.lastNameEN')"
|
||||
for="input-last-name-en"
|
||||
v-model="lastNameEN"
|
||||
/>
|
||||
|
||||
<q-input
|
||||
lazy-rules="ondemand"
|
||||
dense
|
||||
outlined
|
||||
:readonly="readonly"
|
||||
hide-bottom-space
|
||||
class="col-12"
|
||||
:label="$t('general.address')"
|
||||
for="input-address"
|
||||
v-model="address"
|
||||
/>
|
||||
<DatePicker
|
||||
:label="$t('customer.form.issueDate')"
|
||||
v-model="firstName"
|
||||
class="col-6"
|
||||
:id="`${prefixId}-input-issue-date`"
|
||||
:readonly="readonly"
|
||||
clearable
|
||||
/>
|
||||
|
||||
<DatePicker
|
||||
:label="$t('customer.form.passportExpiryDate')"
|
||||
v-model="firstName"
|
||||
class="col-6"
|
||||
:id="`${prefixId}-input-passport-expiry-date`"
|
||||
:readonly="readonly"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,29 +1,40 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { SaveButton, UndoButton } from 'components/button';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { SaveButton, UndoButton, CloseButton } from 'components/button';
|
||||
import { dialog } from 'stores/utils';
|
||||
|
||||
import { VuePDF, usePDF } from '@tato30/vue-pdf';
|
||||
|
||||
const currentFileUrl = defineModel<string>('currentFileUrl');
|
||||
const { pdf, pages } = usePDF(currentFileUrl);
|
||||
const currentFileSelected = ref<string>('');
|
||||
const file = defineModel<
|
||||
{
|
||||
group?: string;
|
||||
url?: string;
|
||||
file?: File;
|
||||
}[]
|
||||
>('file', {
|
||||
default: [],
|
||||
});
|
||||
|
||||
const selected = defineModel<string>('selected');
|
||||
const file = defineModel<File | null>('file');
|
||||
const currentFile = computed(() => file.value.at(currentIndex.value));
|
||||
const statusOcr = defineModel<boolean>('statusOcr', { default: false });
|
||||
const currentMode = ref<string>('');
|
||||
const currentIndex = ref(0);
|
||||
|
||||
const scale = ref(1);
|
||||
const page = ref(1);
|
||||
|
||||
const currentTab = ref<string>('information');
|
||||
|
||||
const currentIndexDropdownList = ref(0);
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
tree?: { label: string; children: { label: string }[] }[];
|
||||
dropdownList?: string[];
|
||||
treeFile: { label: string; file: { label: string }[] }[];
|
||||
readonly?: boolean;
|
||||
dropdownList?: { label: string; value: string }[];
|
||||
hideAction?: boolean;
|
||||
}>(),
|
||||
{
|
||||
tree: () => [],
|
||||
treeFile: () => [],
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -47,73 +58,114 @@ function change(e: Event) {
|
|||
const reader = new FileReader();
|
||||
reader.readAsDataURL(_file);
|
||||
reader.onload = () => {
|
||||
currentFileUrl.value = reader.result as string;
|
||||
if (file.value[currentIndex.value]) {
|
||||
file.value[currentIndex.value].url = reader.result as string;
|
||||
}
|
||||
};
|
||||
|
||||
if (_file) file.value = _file;
|
||||
if (_file && file.value[currentIndex.value]) {
|
||||
file.value[currentIndex.value].file = _file;
|
||||
file.value[currentIndex.value].group =
|
||||
props.dropdownList?.[currentIndexDropdownList.value].value;
|
||||
} else {
|
||||
file.value.push({
|
||||
group: props.dropdownList?.[currentIndexDropdownList.value].value,
|
||||
file: _file,
|
||||
});
|
||||
}
|
||||
|
||||
statusOcr.value = true;
|
||||
|
||||
emit(
|
||||
'sendOcr',
|
||||
props.dropdownList?.[currentIndexDropdownList.value] || '',
|
||||
props.dropdownList?.[currentIndexDropdownList.value].value || '',
|
||||
inputFile?.files?.[0],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const tabsList = [
|
||||
{
|
||||
label: 'information',
|
||||
name: 'information',
|
||||
},
|
||||
{
|
||||
label: 'document',
|
||||
name: 'document',
|
||||
},
|
||||
];
|
||||
watch(currentFileSelected, () => {
|
||||
file.value.findIndex((v, i) => {
|
||||
if (v.url?.includes(currentFileSelected.value)) {
|
||||
currentIndex.value = i;
|
||||
currentMode.value =
|
||||
props.dropdownList?.[currentIndexDropdownList.value].label || 'other';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'sendOcr', dropdown: string, file?: File): void;
|
||||
(e: 'save', เgroup: string, file?: File): void;
|
||||
(e: 'deleteFile', filename: string): void;
|
||||
}>();
|
||||
|
||||
const { pdf, pages } = usePDF(computed(() => currentFile.value?.url));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="full-height full-width row">
|
||||
<div>
|
||||
<div class="full-width row no-wrap wrapper">
|
||||
<div class="col column no-wrap">
|
||||
<div class="q-pa-sm text-center bordered" style="height: 50px">
|
||||
<q-btn-dropdown icon="mdi-upload" color="info" label="อัปโหลดเอกสาร">
|
||||
<q-list v-for="(v, i) in dropdownList" :key="v">
|
||||
<q-btn-dropdown
|
||||
:disable="readonly"
|
||||
icon="mdi-upload"
|
||||
color="info"
|
||||
label="อัปโหลดเอกสาร"
|
||||
>
|
||||
<q-list v-for="(v, i) in dropdownList" :key="v.value">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="
|
||||
() => {
|
||||
currentIndexDropdownList = i;
|
||||
const _idx = file.findIndex(
|
||||
(v) => v.group === dropdownList?.[i].value,
|
||||
);
|
||||
if (_idx !== -1) {
|
||||
currentIndex = _idx;
|
||||
} else {
|
||||
file.push({
|
||||
group: dropdownList?.[i].value || 'other',
|
||||
});
|
||||
currentIndex = file.length - 1;
|
||||
}
|
||||
browse();
|
||||
}
|
||||
"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ v }}</q-item-label>
|
||||
<q-item-label>{{ $t(v.label) }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown>
|
||||
</div>
|
||||
|
||||
<div class="full-height bordered-l bordered-b q-pa-sm">
|
||||
<div class="bordered-l bordered-b q-pa-sm col full-height scroll">
|
||||
<q-tree
|
||||
:nodes="tree || []"
|
||||
:nodes="treeFile || []"
|
||||
node-key="label"
|
||||
label-key="label"
|
||||
children-key="file"
|
||||
selected-color="primary"
|
||||
v-model:selected="selected"
|
||||
v-model:selected="currentFileSelected"
|
||||
default-expand-all
|
||||
/>
|
||||
>
|
||||
<template v-slot:default-header="prop">
|
||||
<div class="ellipsis">
|
||||
<q-tooltip>{{ prop.node.label }}</q-tooltip>
|
||||
{{ prop.node.label }}
|
||||
</div>
|
||||
</template>
|
||||
</q-tree>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="col column no-wrap">
|
||||
<div
|
||||
class="bordered row items-center justify-evenly q-pa-sm"
|
||||
class="bordered row items-center justify-evenly q-pa-sm no-wrap"
|
||||
style="height: 50px"
|
||||
>
|
||||
<q-btn
|
||||
|
|
@ -125,7 +177,7 @@ const emit = defineEmits<{
|
|||
id="btn-prev-page-top"
|
||||
/>
|
||||
|
||||
<div>Page {{ page }} of {{ pages }}</div>
|
||||
<div class="ellipsis">Page {{ page }} of {{ pages }}</div>
|
||||
|
||||
<q-btn
|
||||
@click="scale = scale > 0.25 ? scale - 0.25 : scale"
|
||||
|
|
@ -149,7 +201,7 @@ const emit = defineEmits<{
|
|||
icon="mdi-magnify-plus-outline"
|
||||
@click="scale = scale < 2 ? scale + 0.25 : scale"
|
||||
>
|
||||
<q-tooltip>{{ $t('zoomIn') }}</q-tooltip>
|
||||
<q-tooltip>{{ $t('general.zoomIn') }}</q-tooltip>
|
||||
</q-btn>
|
||||
|
||||
<q-btn
|
||||
|
|
@ -165,52 +217,97 @@ const emit = defineEmits<{
|
|||
<div
|
||||
class="flex flex-center surface-2 bordered-l bordered-r bordered-b full-height scroll"
|
||||
>
|
||||
<VuePDF
|
||||
v-if="file?.type === 'application/pdf'"
|
||||
class="q-py-md"
|
||||
:pdf="pdf"
|
||||
:page="page"
|
||||
:scale="scale"
|
||||
/>
|
||||
<q-img v-else class="q-py-md full-width" :src="currentFileUrl" />
|
||||
<template v-if="statusOcr">
|
||||
<q-spinner color="primary" size="3em" :thickness="2" />
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<VuePDF
|
||||
v-if="
|
||||
currentFile?.url?.split('?').at(0)?.endsWith('.pdf') ||
|
||||
currentFile?.file?.type === 'application/pdf'
|
||||
"
|
||||
class="q-py-md"
|
||||
:pdf="pdf"
|
||||
:page="page"
|
||||
:scale="scale"
|
||||
/>
|
||||
|
||||
<q-img v-else class="q-py-md full-width" :src="currentFile?.url" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-4">
|
||||
<div class="col-5 column no-wrap">
|
||||
<div
|
||||
class="bordered row items-center justify-between q-pa-sm"
|
||||
style="height: 50px"
|
||||
>
|
||||
ข้อมูลหนังสือเดินทาง
|
||||
|
||||
<div class="row">
|
||||
{{ $t(currentMode) }}
|
||||
<div class="row" v-if="!hideAction">
|
||||
<UndoButton icon-only type="button" />
|
||||
<SaveButton icon-only type="button" />
|
||||
<SaveButton
|
||||
icon-only
|
||||
type="button"
|
||||
@click="
|
||||
$emit(
|
||||
'save',
|
||||
dropdownList?.[currentIndexDropdownList].value || '',
|
||||
inputFile?.files?.[0],
|
||||
)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bordered-r bordered-b full-height">
|
||||
<q-tabs
|
||||
dense
|
||||
inline-label
|
||||
mobile-arrows
|
||||
v-model="currentTab"
|
||||
active-class="active-tab text-weight-bold"
|
||||
class="app-text-muted full-width"
|
||||
align="left"
|
||||
>
|
||||
<q-tab
|
||||
:id="`tab-${tab.label}`"
|
||||
v-for="tab in tabsList"
|
||||
v-bind:key="tab.name"
|
||||
class="content-tab text-capitalize"
|
||||
:name="tab.name"
|
||||
:label="$t(tab.label)"
|
||||
<div class="q-pa-sm bordered-r bordered-b full-height col scroll">
|
||||
<slot name="form" :mode="currentMode" />
|
||||
|
||||
<div class="row items-center">
|
||||
{{ currentFileSelected }}
|
||||
<CloseButton
|
||||
icon-only
|
||||
v-if="!readonly"
|
||||
type="button"
|
||||
class="q-ml-sm"
|
||||
@click="
|
||||
() => {
|
||||
const tempValue = treeFile.find(
|
||||
(v) => v.label === $t(`customer.typeFile.${currentMode}`),
|
||||
);
|
||||
|
||||
if (!tempValue) return;
|
||||
|
||||
const idx = tempValue.file?.findIndex(
|
||||
(v) => v.label === currentFileSelected,
|
||||
);
|
||||
|
||||
dialog({
|
||||
color: 'negative',
|
||||
icon: 'mdi-alert',
|
||||
title: $t('dialog.title.confirmDelete'),
|
||||
actionText: $t('general.delete'),
|
||||
persistent: true,
|
||||
message: $t('dialog.message.confirmDelete'),
|
||||
action: async () => {
|
||||
$emit('deleteFile', currentFileSelected);
|
||||
|
||||
currentFileSelected = tempValue.file?.[idx - 1].label || '';
|
||||
},
|
||||
|
||||
cancel: () => {},
|
||||
});
|
||||
}
|
||||
"
|
||||
/>
|
||||
</q-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss"></style>
|
||||
<style lang="scss">
|
||||
.wrapper > * {
|
||||
height: 300px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
export { default as UploadFile } from './UploadFile.vue';
|
||||
export { default as FormCitizen } from './FormCitizen.vue';
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ export default {
|
|||
age: 'Age',
|
||||
nationality: 'Nationalality',
|
||||
times: 'No. {number}',
|
||||
uploadFile: 'Upload File',
|
||||
},
|
||||
menu: {
|
||||
dashboard: 'Dashboard',
|
||||
|
|
@ -238,6 +239,17 @@ export default {
|
|||
},
|
||||
},
|
||||
customer: {
|
||||
typeFile: {
|
||||
citizenId: 'National ID card',
|
||||
registrationBook: 'Household registration',
|
||||
houseMap: 'House map',
|
||||
businessRegistration: 'Commercial registration',
|
||||
dbdCertificate: 'DBD Certificate',
|
||||
VatRegistrationCertificate: 'VAT Registration Certificate',
|
||||
powerOfAttorney: 'Power of Attorney',
|
||||
others: 'Others',
|
||||
},
|
||||
|
||||
employer: 'Employer',
|
||||
employerLegalEntity: 'Legal Entity',
|
||||
employerNaturalPerson: 'Natrual Person',
|
||||
|
|
@ -255,6 +267,11 @@ export default {
|
|||
miss: 'Miss.',
|
||||
},
|
||||
|
||||
citizenId: 'Citizen ID',
|
||||
religion: 'Religion',
|
||||
issueDate: 'Issue Date',
|
||||
passportExpiryDate: 'Passport Expiry Date',
|
||||
|
||||
firstName: 'First Name in Thai',
|
||||
lastName: 'Last Name in Thai',
|
||||
firstNameEN: 'First Name in English',
|
||||
|
|
@ -385,6 +402,20 @@ export default {
|
|||
mother: 'Mother',
|
||||
motherBirthPlace: 'Mother Birth Place',
|
||||
},
|
||||
fileType: {
|
||||
passport: 'Passport',
|
||||
visa: 'VISA',
|
||||
tm6: 'TM.6',
|
||||
workPermit: 'Work Permit',
|
||||
noticeJobEmployment: 'Foreign Worker Employment Notification Form',
|
||||
noticeJobEntry:
|
||||
'Foreign Worker Employment Commencement Notification Form',
|
||||
historyJob: 'Employment History Form',
|
||||
acceptJob:
|
||||
'Acknowledgement of Foreign Worker Employment Notification Form',
|
||||
receipt: 'Receipt',
|
||||
other: 'Other',
|
||||
},
|
||||
},
|
||||
customerBranch: {
|
||||
tab: {
|
||||
|
|
@ -392,7 +423,7 @@ export default {
|
|||
address: 'Address',
|
||||
business: 'Business',
|
||||
contact: 'Contact',
|
||||
attachment: 'Attachment',
|
||||
attachment: 'Upload Document',
|
||||
},
|
||||
form: {
|
||||
title: 'Branch',
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ export default {
|
|||
age: 'อายุ',
|
||||
nationality: 'สัญชาติ',
|
||||
times: 'ครั้งที่ {number}',
|
||||
uploadFile: 'อัปโหลดไฟล์',
|
||||
},
|
||||
menu: {
|
||||
dashboard: 'แดชบอร์ด',
|
||||
|
|
@ -239,6 +240,16 @@ export default {
|
|||
},
|
||||
},
|
||||
customer: {
|
||||
typeFile: {
|
||||
citizenId: 'บัตรประจำตัวประชาชน',
|
||||
registrationBook: 'ทะเบียนบ้าน',
|
||||
houseMap: 'แผนที่ (บ้าน)',
|
||||
businessRegistration: 'ทะเบียนพาณิชย์',
|
||||
dbdCertificate: 'หนังสือรับรอง (DBD)',
|
||||
VatRegistrationCertificate: 'ภ.พ.20',
|
||||
powerOfAttorney: 'หนังสือมอบอำนาจ',
|
||||
others: 'อื่นๆ',
|
||||
},
|
||||
employer: 'นายจ้าง',
|
||||
employee: 'ลูกจ้าง',
|
||||
employerLegalEntity: 'นิติบุคคล',
|
||||
|
|
@ -256,6 +267,11 @@ export default {
|
|||
miss: 'Miss.',
|
||||
},
|
||||
|
||||
citizenId: 'บัตรประจำตัวประชาชน',
|
||||
religion: 'ศาสนา',
|
||||
issueDate: 'วันที่ออกหนังสือ',
|
||||
passportExpiryDate: 'วันหiมดอายุหนังสือเดินทาง',
|
||||
|
||||
firstName: 'ชื่อ ภาษาไทย',
|
||||
lastName: 'นามสกุล ภาษาไทย',
|
||||
firstNameEN: 'ชื่อ ภาษาอังกฤษ',
|
||||
|
|
@ -385,6 +401,18 @@ export default {
|
|||
mother: 'มารดา',
|
||||
motherBirthPlace: 'สถานที่เกิดของมารดา',
|
||||
},
|
||||
fileType: {
|
||||
passport: 'ข้อมูลหนังสือการเดินทาง',
|
||||
visa: 'ข้อมูลการตรวจลงตรา',
|
||||
tm6: 'ตม.6',
|
||||
workPermit: 'ใบอนุญาตทำงาน',
|
||||
noticeJobEmployment: 'แบบแจ้งการจ้างคนต่างด้าวทำงาน',
|
||||
noticeJobEntry: 'แบบแจ้งเข้าทำงานของคนต่างด้าว',
|
||||
historyJob: 'ใบคัดประวัติระบบจัดหางาน',
|
||||
acceptJob: 'ใบตอบรับการแจ้งเกี่ยวกับการทำงานของคนต่างด้าว',
|
||||
receipt: 'ใบเสร็จรับเงิน',
|
||||
other: 'อื่นๆ',
|
||||
},
|
||||
},
|
||||
customerBranch: {
|
||||
tab: {
|
||||
|
|
@ -392,7 +420,7 @@ export default {
|
|||
address: 'ที่อยู่',
|
||||
business: 'ธุรกิจ',
|
||||
contact: 'ติดต่อ',
|
||||
attachment: 'เอกสารเพิ่มเติม',
|
||||
attachment: 'อัปโหลดเอกสาร',
|
||||
},
|
||||
form: {
|
||||
title: 'สาขา',
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ import {
|
|||
columnsCustomer,
|
||||
columnsEmployee,
|
||||
formMenuIconEmployee,
|
||||
uploadFileList,
|
||||
uploadFileListEmployee,
|
||||
uploadFileListCustomer,
|
||||
} from './constant';
|
||||
import { useCustomerForm, useEmployeeForm } from './form';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
|
@ -1871,6 +1872,7 @@ const emptyCreateDialog = ref(false);
|
|||
<EmployerFormBranch
|
||||
v-if="!!customerFormState.editCustomerId"
|
||||
:index="idx"
|
||||
v-model:customer="customerFormData"
|
||||
v-model:customer-branch="customerFormData.customerBranch[idx]"
|
||||
:customer-type="customerFormData.customerType"
|
||||
:customer-name="`${customerFormData.firstName} ${customerFormData.lastName}`"
|
||||
|
|
@ -2049,6 +2051,11 @@ const emptyCreateDialog = ref(false);
|
|||
anchor: 'form-visa',
|
||||
tab: 'personalInfo',
|
||||
},
|
||||
{
|
||||
name: $t('general.uploadFile'),
|
||||
anchor: 'drawer-info-file-upload',
|
||||
tab: 'personalInfo',
|
||||
},
|
||||
...(currentFromDataEmployee.employeeCheckup?.map((v, i) => ({
|
||||
name: $t('general.times', { number: i + 1 }),
|
||||
anchor: `form-employee-checkup-${i}`,
|
||||
|
|
@ -2160,6 +2167,7 @@ const emptyCreateDialog = ref(false);
|
|||
employee
|
||||
separator
|
||||
title="customerEmployee.form.group.personalInfo"
|
||||
:readonly="!employeeFormState.isEmployeeEdit"
|
||||
v-model:open="employeeFormState.dialogModal"
|
||||
v-model:prefixName="currentFromDataEmployee.namePrefix"
|
||||
v-model:firstName="currentFromDataEmployee.firstName"
|
||||
|
|
@ -2176,6 +2184,7 @@ const emptyCreateDialog = ref(false);
|
|||
<AddressForm
|
||||
id="form-personal-address"
|
||||
prefix-id="form-employee"
|
||||
:readonly="!employeeFormState.isEmployeeEdit"
|
||||
v-model:same-with-employer="
|
||||
employeeFormState.formDataEmployeeSameAddr
|
||||
"
|
||||
|
|
@ -2197,6 +2206,7 @@ const emptyCreateDialog = ref(false);
|
|||
outlined
|
||||
separator
|
||||
:title="$t('customerEmployee.form.group.passport')"
|
||||
:readonly="!employeeFormState.isEmployeeEdit"
|
||||
v-model:passport-type="currentFromDataEmployee.passportType"
|
||||
v-model:passport-number="currentFromDataEmployee.passportNumber"
|
||||
v-model:passport-issue-date="
|
||||
|
|
@ -2223,6 +2233,7 @@ const emptyCreateDialog = ref(false);
|
|||
dense
|
||||
outlined
|
||||
title="customerEmployee.form.group.visa"
|
||||
:readonly="!employeeFormState.isEmployeeEdit"
|
||||
v-model:visa-type="currentFromDataEmployee.visaType"
|
||||
v-model:visa-number="currentFromDataEmployee.visaNumber"
|
||||
v-model:visa-issue-date="currentFromDataEmployee.visaIssueDate"
|
||||
|
|
@ -2237,6 +2248,84 @@ const emptyCreateDialog = ref(false);
|
|||
v-model:entry-date="currentFromDataEmployee.entryDate"
|
||||
class="q-mb-xl"
|
||||
/>
|
||||
|
||||
<div class="row q-mb-md" id="drawer-info-file-upload">
|
||||
<div class="col-12 q-pb-sm text-weight-bold text-body1">
|
||||
<q-icon
|
||||
flat
|
||||
size="xs"
|
||||
class="q-pa-sm rounded q-mr-xs"
|
||||
color="info"
|
||||
name="mdi-upload"
|
||||
style="background-color: var(--surface-3)"
|
||||
/>
|
||||
{{ $t(`general.uploadFile`) }}
|
||||
</div>
|
||||
<UploadFile
|
||||
:tree-file="
|
||||
Object.values(
|
||||
currentFromDataEmployee.file?.reduce<
|
||||
Record<
|
||||
string,
|
||||
{ label: string; file: { label: string }[] }
|
||||
>
|
||||
>((a, c) => {
|
||||
const _group = c.group || 'other';
|
||||
if (!a[_group]) {
|
||||
a[_group] = {
|
||||
label: $t(
|
||||
uploadFileListEmployee.find(
|
||||
(v) => v.value === _group,
|
||||
)?.label || _group,
|
||||
),
|
||||
file: [
|
||||
{
|
||||
label:
|
||||
c.name ||
|
||||
`${c.group}-${c.file?.name || Date.now()}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
} else {
|
||||
a[_group].file.push({
|
||||
label:
|
||||
c.name ||
|
||||
`${c.group}-${c.file?.name || Date.now()}`,
|
||||
});
|
||||
}
|
||||
return a;
|
||||
}, {}) || {},
|
||||
)
|
||||
"
|
||||
v-model:file="currentFromDataEmployee.file"
|
||||
hide-action
|
||||
v-model:status-ocr="employeeFormState.ocr"
|
||||
:readonly="!employeeFormState.isEmployeeEdit"
|
||||
:dropdown-list="uploadFileListEmployee"
|
||||
@delete-file="
|
||||
async (filename) => {
|
||||
if (currentFromDataEmployee.id) {
|
||||
const result = await employeeStore.deleteAttachment(
|
||||
currentFromDataEmployee.id,
|
||||
filename,
|
||||
);
|
||||
if (result) {
|
||||
currentFromDataEmployee.file =
|
||||
currentFromDataEmployee.file?.filter(
|
||||
(v) => v.name !== filename,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
"
|
||||
@send-ocr="
|
||||
async (_, file) => {
|
||||
if (file) await ocrStore.sendOcr({ file });
|
||||
employeeFormState.ocr = false;
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="employeeFormState.currentTab === 'healthCheck'">
|
||||
|
|
@ -2338,6 +2427,7 @@ const emptyCreateDialog = ref(false);
|
|||
}
|
||||
"
|
||||
/>
|
||||
a
|
||||
</template>
|
||||
|
||||
<template v-if="employeeFormState.currentTab === 'other'">
|
||||
|
|
@ -2466,8 +2556,8 @@ const emptyCreateDialog = ref(false);
|
|||
"
|
||||
:show="
|
||||
async () => {
|
||||
await fetchListOfOptionBranch();
|
||||
customerFormStore.resetForm(customerFormState.dialogType === 'create');
|
||||
// await fetchListOfOptionBranch();
|
||||
// customerFormStore.resetForm(true);
|
||||
}
|
||||
"
|
||||
:before-close="
|
||||
|
|
@ -2477,6 +2567,7 @@ const emptyCreateDialog = ref(false);
|
|||
return false;
|
||||
} else {
|
||||
fetchListCustomer();
|
||||
customerFormStore.resetForm(true);
|
||||
customerFormState.branchIndex = -1;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -2515,10 +2606,15 @@ const emptyCreateDialog = ref(false);
|
|||
name: $t('form.field.basicInformation'),
|
||||
anchor: 'form-basic-info-customer',
|
||||
},
|
||||
{
|
||||
name: $t('customerBranch.tab.attachment'),
|
||||
anchor: 'form-upload-file-customer',
|
||||
},
|
||||
{
|
||||
name: $t('customer.form.group.branch'),
|
||||
anchor: 'form-branch-customer-branch',
|
||||
},
|
||||
|
||||
...(customerFormData.customerBranch?.map((v, i) => ({
|
||||
name:
|
||||
i === 0
|
||||
|
|
@ -2546,7 +2642,6 @@ const emptyCreateDialog = ref(false);
|
|||
style="height: 100%; max-height: 100%; overflow-y: auto"
|
||||
>
|
||||
<EmployerFormBasicInfo
|
||||
class="q-mb-xl"
|
||||
:readonly="
|
||||
(customerFormState.dialogType === 'edit' &&
|
||||
customerFormState.readonly === true) ||
|
||||
|
|
@ -2577,6 +2672,19 @@ const emptyCreateDialog = ref(false);
|
|||
v-model:birth-date="customerFormData.birthDate"
|
||||
/>
|
||||
|
||||
<!-- <div class="row q-col-gutter-sm q-mb-xl">
|
||||
<UploadFile
|
||||
id="form-upload-file-customer"
|
||||
class="q-mb-xl"
|
||||
hide-action
|
||||
:dropdown-list="uploadFileList"
|
||||
v-model:file="customerFormState.file"
|
||||
@send-ocr="
|
||||
(group: any, file: any) => ocrStore.sendOcr({ file })
|
||||
"
|
||||
/>
|
||||
</div> -->
|
||||
|
||||
<div class="row q-col-gutter-sm" id="form-branch-customer-branch">
|
||||
<div
|
||||
class="col-12 text-weight-bold text-body1 row items-center"
|
||||
|
|
@ -2663,9 +2771,33 @@ const emptyCreateDialog = ref(false);
|
|||
);
|
||||
}
|
||||
|
||||
customerFormData.customerBranch[idx].file?.forEach(
|
||||
async (v) => {
|
||||
if (!v.file) return;
|
||||
|
||||
const ext = v.file.name.split('.').at(-1);
|
||||
let filename = v.group + '-' + new Date().getTime();
|
||||
if (ext) filename += `.${ext}`;
|
||||
|
||||
const res = await customerStore.putAttachment({
|
||||
branchId:
|
||||
customerFormData.customerBranch?.[idx].id || '',
|
||||
file: v.file,
|
||||
filename,
|
||||
});
|
||||
|
||||
if (res) {
|
||||
await customerFormStore.assignFormData(
|
||||
customerFormState.editCustomerId,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
await customerFormStore.assignFormData(
|
||||
customerFormState.editCustomerId,
|
||||
);
|
||||
|
||||
customerFormStore.resetForm();
|
||||
}
|
||||
}
|
||||
|
|
@ -2674,9 +2806,11 @@ const emptyCreateDialog = ref(false);
|
|||
<EmployerFormBranch
|
||||
v-if="!!customerFormState.editCustomerId"
|
||||
:index="idx"
|
||||
v-model:customer="customerFormData"
|
||||
v-model:customer-branch="
|
||||
customerFormData.customerBranch[idx]
|
||||
"
|
||||
:tree-file="customerFormState.treeFile"
|
||||
:customer-type="customerFormData.customerType"
|
||||
:customer-name="`${customerFormData.firstName} ${customerFormData.lastName}`"
|
||||
:action-disabled="
|
||||
|
|
@ -2869,7 +3003,7 @@ const emptyCreateDialog = ref(false);
|
|||
},
|
||||
|
||||
{
|
||||
name: $t('อัปโหลดไฟล์'),
|
||||
name: $t('general.uploadFile'),
|
||||
anchor: 'drawer-upload-file',
|
||||
tab: 'personalInfo',
|
||||
},
|
||||
|
|
@ -3062,17 +3196,83 @@ const emptyCreateDialog = ref(false);
|
|||
class="q-mb-xl"
|
||||
/>
|
||||
|
||||
<UploadFile
|
||||
:tree="[]"
|
||||
:dropdown-list="uploadFileList"
|
||||
@send-ocr="
|
||||
async (v: any, f: any) => {
|
||||
console.log(v, f);
|
||||
|
||||
await ocrStore.sendOcr({ file: f });
|
||||
}
|
||||
"
|
||||
/>
|
||||
<div class="row" id="drawer-upload-file">
|
||||
<div class="col-12 q-pb-sm text-weight-bold text-body1">
|
||||
<q-icon
|
||||
flat
|
||||
size="xs"
|
||||
class="q-pa-sm rounded q-mr-xs"
|
||||
color="info"
|
||||
name="mdi-upload"
|
||||
style="background-color: var(--surface-3)"
|
||||
/>
|
||||
{{ $t(`general.uploadFile`) }}
|
||||
</div>
|
||||
<UploadFile
|
||||
:tree-file="
|
||||
Object.values(
|
||||
currentFromDataEmployee.file?.reduce<
|
||||
Record<
|
||||
string,
|
||||
{ label: string; file: { label: string }[] }
|
||||
>
|
||||
>((a, c) => {
|
||||
const _group = c.group || 'other';
|
||||
if (!a[_group]) {
|
||||
a[_group] = {
|
||||
label: $t(
|
||||
uploadFileListEmployee.find(
|
||||
(v) => v.value === _group,
|
||||
)?.label || _group,
|
||||
),
|
||||
file: [
|
||||
{
|
||||
label:
|
||||
c.name ||
|
||||
`${c.group}-${c.file?.name || Date.now()}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
} else {
|
||||
a[_group].file.push({
|
||||
label:
|
||||
c.name ||
|
||||
`${c.group}-${c.file?.name || Date.now()}`,
|
||||
});
|
||||
}
|
||||
return a;
|
||||
}, {}) || {},
|
||||
)
|
||||
"
|
||||
v-model:file="currentFromDataEmployee.file"
|
||||
hide-action
|
||||
v-model:status-ocr="employeeFormState.ocr"
|
||||
:readonly="!employeeFormState.isEmployeeEdit"
|
||||
:dropdown-list="uploadFileListEmployee"
|
||||
@delete-file="
|
||||
async (filename) => {
|
||||
if (currentFromDataEmployee.id) {
|
||||
const result = await employeeStore.deleteAttachment(
|
||||
currentFromDataEmployee.id,
|
||||
filename,
|
||||
);
|
||||
if (result) {
|
||||
currentFromDataEmployee.file =
|
||||
currentFromDataEmployee.file?.filter(
|
||||
(v) => v.name !== filename,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
"
|
||||
@send-ocr="
|
||||
async (_, file) => {
|
||||
if (file) await ocrStore.sendOcr({ file });
|
||||
employeeFormState.ocr = false;
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="employeeFormState.currentTab === 'healthCheck'">
|
||||
<FormEmployeeHealthCheck
|
||||
|
|
|
|||
|
|
@ -5,18 +5,32 @@ import EmployerFormBusiness from './EmployerFormBusiness.vue';
|
|||
import EmployerFormContact from './EmployerFormContact.vue';
|
||||
import { CustomerCreate } from 'stores/customer/types';
|
||||
import EmployerFormAbout from './EmployerFormAbout.vue';
|
||||
import EmployerFormAttachment from './EmployerFormAttachment.vue';
|
||||
import { useCustomerForm } from 'src/pages/03_customer-management/form';
|
||||
|
||||
const customerFormStore = useCustomerForm();
|
||||
import { FormCitizen } from 'components/upload-file/';
|
||||
|
||||
import useOcrStore from 'stores/ocr';
|
||||
|
||||
const ocrStore = useOcrStore();
|
||||
import {
|
||||
SaveButton,
|
||||
EditButton,
|
||||
DeleteButton,
|
||||
UndoButton,
|
||||
} from 'components/button';
|
||||
import UploadFile from 'src/components/upload-file/UploadFile.vue';
|
||||
import { uploadFileListCustomer } from '../../constant';
|
||||
|
||||
const statusOcr = ref(false);
|
||||
|
||||
const customer = defineModel<CustomerCreate>('customer', { required: true });
|
||||
|
||||
const item = defineModel<NonNullable<CustomerCreate['customerBranch']>[number]>(
|
||||
'customerBranch',
|
||||
{ required: true },
|
||||
);
|
||||
|
||||
const tab = ref('main');
|
||||
|
||||
defineEmits<{
|
||||
|
|
@ -33,6 +47,7 @@ defineProps<{
|
|||
prefixId?: string;
|
||||
actionDisabled?: boolean;
|
||||
customerType?: 'CORP' | 'PERS';
|
||||
treeFile?: { label: string; file: { label: string }[] }[];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
|
|
@ -160,10 +175,103 @@ defineProps<{
|
|||
/>
|
||||
</q-tab-panel>
|
||||
<q-tab-panel name="attachment">
|
||||
<EmployerFormAttachment
|
||||
<UploadFile
|
||||
hide-action
|
||||
:readonly="readonly"
|
||||
:dropdown-list="uploadFileListCustomer"
|
||||
v-model:status-ocr="statusOcr"
|
||||
v-model:file="item.file"
|
||||
:tree-file="
|
||||
Object.values(
|
||||
item.file?.reduce<
|
||||
Record<string, { label: string; file: { label: string }[] }>
|
||||
>((a, c) => {
|
||||
const _group = c.group || 'other';
|
||||
console.log(c);
|
||||
|
||||
if (!a[_group]) {
|
||||
a[_group] = {
|
||||
label: $t(
|
||||
uploadFileListCustomer.find((v) => v.value === _group)
|
||||
?.label || _group,
|
||||
),
|
||||
file: [
|
||||
{
|
||||
label:
|
||||
c.name ||
|
||||
`${c.group}-${c.file?.name || Date.now()}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
} else {
|
||||
a[_group].file.push({
|
||||
label:
|
||||
c.name || `${c.group}-${c.file?.name || Date.now()}`,
|
||||
});
|
||||
}
|
||||
return a;
|
||||
}, {}) || {},
|
||||
)
|
||||
"
|
||||
@send-ocr="
|
||||
async (v: any, f: any) => {
|
||||
const res = await ocrStore.sendOcr({ file: f });
|
||||
|
||||
if (res) {
|
||||
const map = res.fields.reduce<Record<string, string>>(
|
||||
(a, c) => {
|
||||
a[c.name] = c.value;
|
||||
return a;
|
||||
},
|
||||
{},
|
||||
);
|
||||
if (!item.citizenId) item.citizenId = map['citizen_id'] || '';
|
||||
if (!item.address) item.address = map['address'] || '';
|
||||
if (!customer.firstName)
|
||||
customer.firstName = map['firstname'] || '';
|
||||
if (!customer.lastName)
|
||||
customer.lastName = map['lastname'] || '';
|
||||
if (!customer.firstNameEN)
|
||||
customer.firstNameEN = map['firstname_en'] || '';
|
||||
if (!customer.lastNameEN)
|
||||
customer.lastNameEN = map['lastname_en'] || '';
|
||||
if (!customer.birthDate)
|
||||
customer.birthDate = new Date(map['birth_date'] || '');
|
||||
}
|
||||
|
||||
statusOcr = false;
|
||||
}
|
||||
"
|
||||
@delete-file="
|
||||
(filename) => {
|
||||
if (!item.id) return;
|
||||
|
||||
customerFormStore.deleteAttachment(
|
||||
{ branchId: item.id, customerId: item.customerId },
|
||||
filename,
|
||||
);
|
||||
}
|
||||
"
|
||||
>
|
||||
<template #form="{ mode }">
|
||||
<FormCitizen
|
||||
v-if="mode === 'citizenId'"
|
||||
orc
|
||||
v-model:citizen-id="item.citizenId"
|
||||
v-model:birth-date="customer.birthDate"
|
||||
v-model:first-name="customer.firstName"
|
||||
v-model:first-name-en="customer.firstNameEN"
|
||||
v-model:last-name="customer.lastName"
|
||||
v-model:last-name-en="customer.lastNameEN"
|
||||
v-model:address="item.address"
|
||||
/>
|
||||
</template>
|
||||
</UploadFile>
|
||||
|
||||
<!-- <EmployerFormAttachment
|
||||
:readonly="readonly"
|
||||
v-model:attachment="item.file"
|
||||
/>
|
||||
/> -->
|
||||
</q-tab-panel>
|
||||
</q-tab-panels>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,93 @@
|
|||
import { QTableProps } from 'quasar';
|
||||
|
||||
export const uploadFileList: string[] = [
|
||||
'ข้อมูลหนังสือการเดินทาง',
|
||||
'ข้อมูลการตรวจลงตรา',
|
||||
'ตม.6',
|
||||
'ใบอนุญาตทำงาน',
|
||||
'แบบแจ้งการจ้างคนต่างด้าวทำงาน',
|
||||
'แบบแจ้งเข้าทำงานของคนต่างด้าว',
|
||||
'ใบคัดประวัติระบบจัดหางาน',
|
||||
'ใบตอบรับการแจ้งเกี่ยวกับการทำงานของคนต่างด้าว',
|
||||
'ใบเสร็จรับเงิน',
|
||||
'อื่นๆ',
|
||||
export const uploadFileListCustomer: {
|
||||
label: string;
|
||||
value: string;
|
||||
}[] = [
|
||||
{
|
||||
label: 'customer.typeFile.citizenId',
|
||||
value: 'citizenId',
|
||||
},
|
||||
{
|
||||
label: 'customer.typeFile.registrationBook',
|
||||
value: 'registrationBook',
|
||||
},
|
||||
|
||||
{
|
||||
label: 'customer.typeFile.houseMap',
|
||||
value: 'houseMap',
|
||||
},
|
||||
|
||||
{
|
||||
label: 'customer.typeFile.businessRegistration',
|
||||
value: 'businessRegistration',
|
||||
},
|
||||
|
||||
{
|
||||
label: 'customer.typeFile.dbdCertificate',
|
||||
value: 'dbdCertificate',
|
||||
},
|
||||
|
||||
{
|
||||
label: 'customer.typeFile.vatRegistrationCertificate',
|
||||
value: 'vatRegistrationCertificate',
|
||||
},
|
||||
|
||||
{
|
||||
label: 'customer.typeFile.powerOfAttorney',
|
||||
value: 'powerOfAttorney',
|
||||
},
|
||||
|
||||
{
|
||||
label: 'customer.typeFile.others',
|
||||
value: 'others',
|
||||
},
|
||||
];
|
||||
|
||||
export const uploadFileListEmployee: {
|
||||
label: string;
|
||||
value: string;
|
||||
}[] = [
|
||||
{
|
||||
label: 'customerEmployee.fileType.passport',
|
||||
value: 'passport',
|
||||
},
|
||||
{
|
||||
label: 'customerEmployee.fileType.visa',
|
||||
value: 'visa',
|
||||
},
|
||||
{
|
||||
label: 'customerEmployee.fileType.tm6',
|
||||
value: 'tm6',
|
||||
},
|
||||
{
|
||||
label: 'customerEmployee.fileType.workPermit',
|
||||
value: 'workPermit',
|
||||
},
|
||||
{
|
||||
label: 'customerEmployee.fileType.noticeJobEmployment',
|
||||
value: 'noticeJobEmployment',
|
||||
},
|
||||
{
|
||||
label: 'customerEmployee.fileType.noticeJobEntry',
|
||||
value: 'noticeJobEntry',
|
||||
},
|
||||
{
|
||||
label: 'customerEmployee.fileType.historyJob',
|
||||
value: 'historyJob',
|
||||
},
|
||||
{
|
||||
label: 'customerEmployee.fileType.acceptJob',
|
||||
value: 'acceptJob',
|
||||
},
|
||||
{
|
||||
label: 'customerEmployee.fileType.receipt',
|
||||
value: 'receipt',
|
||||
},
|
||||
{
|
||||
label: 'customerEmployee.fileType.other',
|
||||
value: 'other',
|
||||
},
|
||||
];
|
||||
|
||||
export const formMenuIconEmployee = [
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { ref, toRaw, watch } from 'vue';
|
|||
import { defineStore } from 'pinia';
|
||||
import { CustomerBranchCreate, CustomerCreate } from 'stores/customer/types';
|
||||
import { Employee, EmployeeCreate } from 'stores/employee/types';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import useMyBranch from 'stores/my-branch';
|
||||
import useCustomerStore from 'stores/customer';
|
||||
|
|
@ -9,6 +10,7 @@ import useEmployeeStore from 'stores/employee';
|
|||
import useFlowStore from 'stores/flow';
|
||||
|
||||
export const useCustomerForm = defineStore('form-customer', () => {
|
||||
const { t } = useI18n();
|
||||
const apiBaseUrl = import.meta.env.VITE_API_BASE_URL;
|
||||
|
||||
const customerStore = useCustomerStore();
|
||||
|
|
@ -46,6 +48,8 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
|||
editCustomerId?: string;
|
||||
editCustomerCode?: string;
|
||||
editCustomerBranchId?: string;
|
||||
treeFile: { label: string; file: { label: string }[] }[];
|
||||
formDataOcr: Record<string, any>;
|
||||
}>({
|
||||
dialogType: 'info',
|
||||
dialogOpen: false,
|
||||
|
|
@ -59,6 +63,8 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
|||
editCustomerId: '',
|
||||
editCustomerBranchId: '',
|
||||
defaultCustomerImageUrl: '',
|
||||
treeFile: [],
|
||||
formDataOcr: {},
|
||||
});
|
||||
|
||||
watch(
|
||||
|
|
@ -66,6 +72,16 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
|||
(v) => (defaultFormData.customerType = v.customerType),
|
||||
);
|
||||
|
||||
async function deleteAttachment(
|
||||
id: { branchId: string; customerId: string },
|
||||
filename: string,
|
||||
) {
|
||||
const res = await customerStore.deleteAttachment(id.branchId, filename);
|
||||
if (res) {
|
||||
assignFormData(id.customerId);
|
||||
}
|
||||
}
|
||||
|
||||
function isFormDataDifferent() {
|
||||
return (
|
||||
JSON.stringify(resetFormData) !== JSON.stringify(currentFormData.value)
|
||||
|
|
@ -82,6 +98,8 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
|||
resetFormData = structuredClone(defaultFormData);
|
||||
resetFormData.registeredBranchId = branchStore.currentMyBranch?.id || '';
|
||||
state.value.editCustomerId = '';
|
||||
state.value.treeFile = [];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -127,41 +145,59 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
|||
resetFormData.birthDate = new Date(data.birthDate);
|
||||
resetFormData.image = null;
|
||||
|
||||
resetFormData.customerBranch = data.branch.map((v) => ({
|
||||
id: v.id,
|
||||
code: v.code || '',
|
||||
customerCode: '',
|
||||
provinceId: v.provinceId,
|
||||
districtId: v.districtId,
|
||||
subDistrictId: v.subDistrictId,
|
||||
wageRate: v.wageRate,
|
||||
payDate: new Date(v.payDate), // Convert the string to a Date object
|
||||
saleEmployee: v.saleEmployee,
|
||||
jobDescription: v.jobDescription,
|
||||
jobPositionEN: v.jobPositionEN,
|
||||
jobPosition: v.jobPosition,
|
||||
businessTypeEN: v.businessTypeEN,
|
||||
businessType: v.businessType,
|
||||
employmentOffice: v.employmentOffice,
|
||||
telephoneNo: v.telephoneNo,
|
||||
email: v.email,
|
||||
addressEN: v.addressEN,
|
||||
address: v.address,
|
||||
workplaceEN: v.workplaceEN,
|
||||
workplace: v.workplace,
|
||||
status: v.status,
|
||||
customerId: v.customerId,
|
||||
citizenId: v.citizenId || '',
|
||||
authorizedCapital: v.authorizedCapital || '',
|
||||
registerDate: new Date(v.registerDate), // Convert the string to a Date object
|
||||
registerNameEN: v.registerNameEN || '',
|
||||
registerName: v.registerName || '',
|
||||
legalPersonNo: v.legalPersonNo || '',
|
||||
registerCompanyName: '',
|
||||
statusSave: true,
|
||||
contactName: v.contactName || '',
|
||||
file: undefined,
|
||||
}));
|
||||
resetFormData.customerBranch = await Promise.all(
|
||||
data.branch.map(async (v) => ({
|
||||
id: v.id,
|
||||
code: v.code || '',
|
||||
customerCode: '',
|
||||
provinceId: v.provinceId,
|
||||
districtId: v.districtId,
|
||||
subDistrictId: v.subDistrictId,
|
||||
wageRate: v.wageRate,
|
||||
payDate: new Date(v.payDate), // Convert the string to a Date object
|
||||
saleEmployee: v.saleEmployee,
|
||||
jobDescription: v.jobDescription,
|
||||
jobPositionEN: v.jobPositionEN,
|
||||
jobPosition: v.jobPosition,
|
||||
businessTypeEN: v.businessTypeEN,
|
||||
businessType: v.businessType,
|
||||
employmentOffice: v.employmentOffice,
|
||||
telephoneNo: v.telephoneNo,
|
||||
email: v.email,
|
||||
addressEN: v.addressEN,
|
||||
address: v.address,
|
||||
workplaceEN: v.workplaceEN,
|
||||
workplace: v.workplace,
|
||||
status: v.status,
|
||||
customerId: v.customerId,
|
||||
citizenId: v.citizenId || '',
|
||||
authorizedCapital: v.authorizedCapital || '',
|
||||
registerDate: new Date(v.registerDate), // Convert the string to a Date object
|
||||
registerNameEN: v.registerNameEN || '',
|
||||
registerName: v.registerName || '',
|
||||
legalPersonNo: v.legalPersonNo || '',
|
||||
registerCompanyName: '',
|
||||
statusSave: true,
|
||||
contactName: v.contactName || '',
|
||||
file: await customerStore.listAttachment(v.id).then(async (r) => {
|
||||
if (r) {
|
||||
return await Promise.all(
|
||||
r.map(async (item) => {
|
||||
const fragment = item.split('-');
|
||||
const group = fragment.length === 1 ? 'other' : fragment.at(0);
|
||||
|
||||
return {
|
||||
url: await customerStore.getAttachment(v.id, item),
|
||||
name: item,
|
||||
group: group,
|
||||
};
|
||||
}),
|
||||
);
|
||||
}
|
||||
return [];
|
||||
}),
|
||||
})),
|
||||
);
|
||||
|
||||
currentFormData.value = structuredClone(resetFormData);
|
||||
}
|
||||
|
|
@ -269,11 +305,13 @@ export const useCustomerForm = defineStore('form-customer', () => {
|
|||
assignFormData,
|
||||
submitFormCustomer,
|
||||
addCurrentCustomerBranch,
|
||||
deleteAttachment,
|
||||
};
|
||||
});
|
||||
|
||||
export const useCustomerBranchForm = defineStore('form-customer-branch', () => {
|
||||
const customerStore = useCustomerStore();
|
||||
const customerFormStore = useCustomerForm();
|
||||
|
||||
const defaultFormData: CustomerBranchCreate & { id?: string } = {
|
||||
code: '',
|
||||
|
|
@ -404,6 +442,10 @@ export const useCustomerBranchForm = defineStore('form-customer-branch', () => {
|
|||
if (!currentFormData.value.id) {
|
||||
const res = await customerStore.createBranch({
|
||||
...currentFormData.value,
|
||||
citizenId:
|
||||
customerFormStore.currentFormData.customerType === 'CORP'
|
||||
? undefined
|
||||
: currentFormData.value.citizenId,
|
||||
customerId: state.value.currentCustomerId,
|
||||
});
|
||||
if (res) return res;
|
||||
|
|
@ -418,8 +460,8 @@ export const useCustomerBranchForm = defineStore('form-customer-branch', () => {
|
|||
|
||||
return {
|
||||
state,
|
||||
initForm,
|
||||
currentFormData,
|
||||
initForm,
|
||||
isFormDataDifferent,
|
||||
submitForm,
|
||||
};
|
||||
|
|
@ -467,6 +509,7 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
|||
zipCode: string;
|
||||
}
|
||||
| undefined;
|
||||
ocr: boolean;
|
||||
}>({
|
||||
currentIndex: -1,
|
||||
statusSavePersonal: false,
|
||||
|
|
@ -484,6 +527,7 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
|||
editReadonly: false,
|
||||
infoEmployeePersonCard: [],
|
||||
formDataEmployeeOwner: undefined,
|
||||
ocr: false,
|
||||
});
|
||||
|
||||
const defaultFormData: EmployeeCreate = {
|
||||
|
|
@ -783,10 +827,12 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
|||
return;
|
||||
}
|
||||
|
||||
const res = await employeeStore.fetchById(id);
|
||||
const _data = await employeeStore.fetchById(id);
|
||||
|
||||
if (res) {
|
||||
state.value.currentEmployee = res;
|
||||
if (_data) {
|
||||
const _attach = await employeeStore.listAttachment(_data.id);
|
||||
|
||||
state.value.currentEmployee = _data;
|
||||
|
||||
const {
|
||||
createdAt,
|
||||
|
|
@ -800,47 +846,61 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
|||
createdBy,
|
||||
updatedBy,
|
||||
profileImageUrl,
|
||||
...playlond
|
||||
} = res;
|
||||
...payload
|
||||
} = _data;
|
||||
|
||||
resetEmployeeData = {
|
||||
...playlond,
|
||||
...payload,
|
||||
provinceId: province?.id,
|
||||
districtId: district?.id,
|
||||
subDistrictId: subDistrict?.id,
|
||||
employeeCheckup: structuredClone(
|
||||
playlond.employeeCheckup?.length === 0
|
||||
payload.employeeCheckup?.length === 0
|
||||
? defaultFormData.employeeCheckup
|
||||
: playlond.employeeCheckup?.map((item) => ({
|
||||
: payload.employeeCheckup?.map((item) => ({
|
||||
...item,
|
||||
statusSave: true,
|
||||
})),
|
||||
),
|
||||
employeeOtherInfo: structuredClone(
|
||||
{
|
||||
...playlond.employeeOtherInfo,
|
||||
statusSave: !!playlond.employeeOtherInfo?.id ? true : false,
|
||||
...payload.employeeOtherInfo,
|
||||
statusSave: !!payload.employeeOtherInfo?.id ? true : false,
|
||||
} || {},
|
||||
),
|
||||
employeeWork: structuredClone(
|
||||
playlond.employeeWork?.length === 0
|
||||
payload.employeeWork?.length === 0
|
||||
? defaultFormData.employeeWork
|
||||
: playlond.employeeWork?.map((item) => ({
|
||||
: payload.employeeWork?.map((item) => ({
|
||||
...item,
|
||||
statusSave: true,
|
||||
})),
|
||||
),
|
||||
file: _attach
|
||||
? await Promise.all(
|
||||
_attach.map(async (name) => {
|
||||
const fragment = name.split('-');
|
||||
const group = fragment.length === 1 ? 'other' : fragment.at(0);
|
||||
|
||||
return {
|
||||
url: await employeeStore.getAttachment(_data.id, name),
|
||||
name,
|
||||
group,
|
||||
};
|
||||
}),
|
||||
)
|
||||
: [],
|
||||
image: null,
|
||||
};
|
||||
|
||||
currentFromDataEmployee.value = structuredClone(resetEmployeeData);
|
||||
const foundBranch = await customerStore.fetchListCustomeBranchById(
|
||||
playlond.customerBranchId,
|
||||
payload.customerBranchId,
|
||||
);
|
||||
|
||||
state.value.currentEmployeeCode = playlond.code;
|
||||
state.value.currentEmployeeCode = payload.code;
|
||||
|
||||
state.value.profileUrl = profileImageUrl || ' ';
|
||||
state.value.profileUrl = profileImageUrl || '';
|
||||
|
||||
profileImageUrl
|
||||
? (state.value.profileSubmit = true)
|
||||
|
|
@ -849,8 +909,8 @@ export const useEmployeeForm = defineStore('form-employee', () => {
|
|||
state.value.formDataEmployeeOwner = { ...foundBranch };
|
||||
|
||||
if (
|
||||
foundBranch.address === playlond.address &&
|
||||
foundBranch.zipCode === playlond.zipCode
|
||||
foundBranch.address === payload.address &&
|
||||
foundBranch.zipCode === payload.zipCode
|
||||
) {
|
||||
state.value.formDataEmployeeSameAddr = true;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import {
|
|||
import axios from 'axios';
|
||||
import useFlowStore from '../flow';
|
||||
import { Employee } from '../employee/types';
|
||||
import { baseUrl } from '../utils';
|
||||
|
||||
const useCustomerStore = defineStore('api-customer', () => {
|
||||
const flowStore = useFlowStore();
|
||||
|
|
@ -208,6 +209,64 @@ const useCustomerStore = defineStore('api-customer', () => {
|
|||
|
||||
return res.data;
|
||||
}
|
||||
|
||||
async function putAttachment(opts: {
|
||||
branchId: string;
|
||||
file: File;
|
||||
filename?: string;
|
||||
}) {
|
||||
const res = await api.put(
|
||||
`/customer-branch/${opts.branchId}/attachment/${opts.filename || opts.file.name}`,
|
||||
opts.file,
|
||||
{
|
||||
headers: { 'X-Rtid': flowStore.rtid, 'Content-Type': opts.file.type },
|
||||
onUploadProgress: (e) => console.log(e),
|
||||
},
|
||||
);
|
||||
|
||||
if (res.status >= 400) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async function deleteAttachment(id: string, filename: string) {
|
||||
const res = await api.delete(
|
||||
`/customer-branch/${id}/attachment/${filename}`,
|
||||
);
|
||||
|
||||
if (res.status >= 400) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
async function listAttachment(id: string) {
|
||||
const res = await api.get<string[]>(`/customer-branch/${id}/attachment`, {
|
||||
headers: { 'X-Rtid': flowStore.rtid },
|
||||
});
|
||||
|
||||
if (res.status >= 400) return false;
|
||||
|
||||
return res.data;
|
||||
}
|
||||
|
||||
async function getAttachment(id: string, filename: string, download = false) {
|
||||
const url = `${baseUrl}/customer-branch/${id}/attachment/${filename}`;
|
||||
const res = await api.get<string>(url);
|
||||
|
||||
if (download) {
|
||||
fetch(res.data)
|
||||
.then(async (res) => await res.blob())
|
||||
.then((blob) => {
|
||||
let a = document.createElement('a');
|
||||
a.download = filename;
|
||||
a.href = window.URL.createObjectURL(blob);
|
||||
a.click();
|
||||
a.remove();
|
||||
});
|
||||
}
|
||||
|
||||
return res.data;
|
||||
}
|
||||
|
||||
async function create(
|
||||
data: CustomerCreate,
|
||||
flow?: {
|
||||
|
|
@ -395,7 +454,7 @@ const useCustomerStore = defineStore('api-customer', () => {
|
|||
});
|
||||
if (!res) return false;
|
||||
|
||||
if (file) await addBranchAttachment(res.data.id, { file });
|
||||
// if (file) await addBranchAttachment(res.data.id, { file });
|
||||
|
||||
return res.data;
|
||||
}
|
||||
|
|
@ -443,7 +502,7 @@ const useCustomerStore = defineStore('api-customer', () => {
|
|||
},
|
||||
);
|
||||
|
||||
if (file) await addBranchAttachment(id, { file });
|
||||
// if (file) await addBranchAttachment(id, { file });
|
||||
|
||||
if (!res) return false;
|
||||
|
||||
|
|
@ -472,68 +531,6 @@ const useCustomerStore = defineStore('api-customer', () => {
|
|||
return false;
|
||||
}
|
||||
|
||||
async function addBranchAttachment(
|
||||
branchId: string,
|
||||
payload: BranchAttachmentCreate,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
const list: { name: string; file: File }[] = [];
|
||||
|
||||
payload.file.forEach((v) => {
|
||||
let filename = v.name;
|
||||
|
||||
if (list.some((v) => v.name === filename)) {
|
||||
const dotIndex = filename.lastIndexOf('.');
|
||||
const originalName =
|
||||
dotIndex !== -1 && !filename.startsWith('.')
|
||||
? filename.slice(0, dotIndex)
|
||||
: filename;
|
||||
const extension =
|
||||
dotIndex !== -1 && !filename.startsWith('.')
|
||||
? filename.slice(dotIndex)
|
||||
: '';
|
||||
|
||||
let i = 0;
|
||||
|
||||
while (list.some((v) => v.name === filename)) {
|
||||
filename = `${originalName} (${++i})`;
|
||||
if (dotIndex !== -1) filename += extension;
|
||||
}
|
||||
}
|
||||
|
||||
list.push({ name: filename, file: v });
|
||||
});
|
||||
|
||||
const res = await api.post<(BranchAttachment & { uploadUrl: string })[]>(
|
||||
`/customer-branch/${branchId}/attachment`,
|
||||
{ file: list.map((v) => v.name) },
|
||||
{
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
res.data.map(async (a) => {
|
||||
const found = list.find((b) => b.name === a.name)!;
|
||||
|
||||
await axios
|
||||
.put(a.uploadUrl, found.file, {
|
||||
headers: { 'Content-Type': found.file.type },
|
||||
onUploadProgress: (e) => console.log(e),
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
async function fetchListCustomeBranchById(
|
||||
branchId: string,
|
||||
flow?: {
|
||||
|
|
@ -576,6 +573,11 @@ const useCustomerStore = defineStore('api-customer', () => {
|
|||
fetchListCustomeBranchById,
|
||||
|
||||
fetchBranchEmployee,
|
||||
|
||||
listAttachment,
|
||||
getAttachment,
|
||||
putAttachment,
|
||||
deleteAttachment,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,12 @@ export type CustomerBranchCreate = {
|
|||
registerCompanyName: string;
|
||||
|
||||
statusSave?: boolean;
|
||||
file?: File[];
|
||||
file?: {
|
||||
name?: string;
|
||||
group?: string;
|
||||
url?: string;
|
||||
file?: File;
|
||||
}[];
|
||||
|
||||
// id?: string;
|
||||
// code?: string;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import {
|
|||
import { CustomerBranch } from '../customer/types';
|
||||
import axios from 'axios';
|
||||
import useFlowStore from '../flow';
|
||||
import { baseUrl } from '../utils';
|
||||
|
||||
const useEmployeeStore = defineStore('api-employee', () => {
|
||||
const flowStore = useFlowStore();
|
||||
|
|
@ -31,22 +32,15 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
return false;
|
||||
}
|
||||
|
||||
async function fetchList(
|
||||
opts?: {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
query?: string;
|
||||
gender?: string;
|
||||
status?: Status;
|
||||
zipCode?: string;
|
||||
customerId?: string;
|
||||
},
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
async function fetchList(opts?: {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
query?: string;
|
||||
gender?: string;
|
||||
status?: Status;
|
||||
zipCode?: string;
|
||||
customerId?: string;
|
||||
}) {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
for (const [k, v] of Object.entries(opts || {})) {
|
||||
|
|
@ -58,11 +52,7 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
const res = await api.get<Pagination<Employee[]>>(
|
||||
`/employee${(params && '?'.concat(query)) || ''}`,
|
||||
{
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
headers: { 'X-Rtid': flowStore.rtid },
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -73,58 +63,54 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
return false;
|
||||
}
|
||||
|
||||
async function create(
|
||||
data: EmployeeCreate,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
const { id, code, image, ...payload } = data;
|
||||
async function create(data: EmployeeCreate) {
|
||||
const { id, code, image, file, ...payload } = data;
|
||||
const res = await api.post<
|
||||
Employee & { profileImageUrl: string; profileImageUploadUrl: string }
|
||||
>('/employee', payload, {
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
headers: { 'X-Rtid': flowStore.rtid },
|
||||
});
|
||||
|
||||
image &&
|
||||
(await axios
|
||||
.put(res.data.profileImageUploadUrl, image, {
|
||||
headers: { 'Content-Type': image?.type },
|
||||
onUploadProgress: (e) => console.log(e),
|
||||
})
|
||||
.catch((e) => console.error(e)));
|
||||
|
||||
if (!res) return false;
|
||||
|
||||
if (res.data.id) {
|
||||
if (image) {
|
||||
await api
|
||||
.put(`/employee/${res.data.id}/image`, image, {
|
||||
headers: { 'Content-Type': image?.type },
|
||||
onUploadProgress: (e) => console.log(e),
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
}
|
||||
if (file) {
|
||||
const attachmentUpload = file.map(async ({ group, file }) => {
|
||||
if (file) {
|
||||
const _name = file.name;
|
||||
const _ext = _name.split('.').at(-1);
|
||||
|
||||
let filename = (group || 'other') + '-' + Date.now();
|
||||
|
||||
if (_ext) filename = filename + '.' + _ext;
|
||||
|
||||
await uploadAttachment(res.data.id, file, filename);
|
||||
}
|
||||
});
|
||||
await Promise.all(attachmentUpload);
|
||||
}
|
||||
}
|
||||
|
||||
return res.data;
|
||||
}
|
||||
|
||||
async function createEmployeeCheckup(
|
||||
employeeId: string,
|
||||
data: EmployeeCheckupCreate,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
const { id, statusSave, ...payload } = data;
|
||||
const res = await api.post<EmployeeCheckupCreate>(
|
||||
`/employee/${employeeId}/checkup`,
|
||||
{ ...payload },
|
||||
{
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
},
|
||||
{ headers: { 'X-Rtid': flowStore.rtid } },
|
||||
);
|
||||
|
||||
if (!res) return false;
|
||||
|
|
@ -135,23 +121,12 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
async function createEmployeeWork(
|
||||
employeeId: string,
|
||||
data: EmployeeWorkCreate,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
const { id, ...payload } = data;
|
||||
const res = await api.post<EmployeeWorkCreate>(
|
||||
`/employee/${employeeId}/work`,
|
||||
{ ...payload },
|
||||
{
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
},
|
||||
{ headers: { 'X-Rtid': flowStore.rtid } },
|
||||
);
|
||||
|
||||
if (!res) return false;
|
||||
|
|
@ -162,22 +137,13 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
async function createEmployeeOtherInfo(
|
||||
employeeId: string,
|
||||
data: EmployeeOtherCreate,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
const { id, statusSave, ...payload } = data;
|
||||
const res = await api.post<EmployeeOtherCreate>(
|
||||
`/employee/${employeeId}/other-info`,
|
||||
{ ...payload },
|
||||
{
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
headers: { 'X-Rtid': flowStore.rtid },
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -189,11 +155,6 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
async function editByIdEmployeeCheckup(
|
||||
employeeOfId: string,
|
||||
data: Partial<EmployeeCheckupCreate>,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
const {
|
||||
id,
|
||||
|
|
@ -208,13 +169,7 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
const res = await api.put<EmployeeCheckupCreate>(
|
||||
`/employee/${employeeOfId}/checkup/${id}`,
|
||||
{ ...payload },
|
||||
{
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
},
|
||||
{ headers: { 'X-Rtid': flowStore.rtid } },
|
||||
);
|
||||
|
||||
if (!res) return false;
|
||||
|
|
@ -225,11 +180,6 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
async function editByIdEmployeeWork(
|
||||
employeeOfId: string,
|
||||
data: Partial<EmployeeWorkCreate>,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
const {
|
||||
id,
|
||||
|
|
@ -244,13 +194,7 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
const res = await api.put<EmployeeWorkCreate>(
|
||||
`/employee/${employeeOfId}/work/${id}`,
|
||||
{ ...payload },
|
||||
{
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
},
|
||||
{ headers: { 'X-Rtid': flowStore.rtid } },
|
||||
);
|
||||
|
||||
if (!res) return false;
|
||||
|
|
@ -261,11 +205,6 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
async function editByIdEmployeeOtherInfo(
|
||||
employeeOfId: string,
|
||||
data: Partial<EmployeeOtherCreate>,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
const {
|
||||
id,
|
||||
|
|
@ -280,13 +219,7 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
const res = await api.put<EmployeeOtherCreate>(
|
||||
`/employee/${employeeOfId}/other-info/${id}`,
|
||||
{ ...payload },
|
||||
{
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
},
|
||||
{ headers: { 'X-Rtid': flowStore.rtid } },
|
||||
);
|
||||
|
||||
if (!res) return false;
|
||||
|
|
@ -294,59 +227,50 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
return res.data;
|
||||
}
|
||||
|
||||
async function editById(
|
||||
employeeId: string,
|
||||
data: Partial<EmployeeCreate>,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
const { id, code, image, ...payload } = data;
|
||||
async function editById(employeeId: string, data: Partial<EmployeeCreate>) {
|
||||
const { id, code, image, file, ...payload } = data;
|
||||
const res = await api.put<
|
||||
Employee & { imageUrl: string; profileImageUploadUrl: string }
|
||||
>(`/employee/${employeeId}`, payload, {
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
headers: { 'X-Rtid': flowStore.rtid },
|
||||
});
|
||||
|
||||
image &&
|
||||
(await axios
|
||||
.put(res.data.profileImageUploadUrl, image, {
|
||||
headers: { 'Content-Type': image.type },
|
||||
if (!res) return false;
|
||||
|
||||
if (image) {
|
||||
await api
|
||||
.put(`/employee/${employeeId}/image`, image, {
|
||||
headers: { 'Content-Type': image?.type },
|
||||
onUploadProgress: (e) => console.log(e),
|
||||
})
|
||||
.catch((e) => console.error(e)));
|
||||
.catch((e) => console.error(e));
|
||||
}
|
||||
if (file) {
|
||||
const attachmentUpload = file.map(async ({ group, file }) => {
|
||||
if (file) {
|
||||
const _name = file.name;
|
||||
const _ext = _name.split('.').at(-1);
|
||||
|
||||
if (!res) return false;
|
||||
let filename = (group || 'other') + '-' + Date.now();
|
||||
|
||||
if (_ext) filename = filename + '.' + _ext;
|
||||
|
||||
await uploadAttachment(employeeId, file, filename);
|
||||
}
|
||||
});
|
||||
await Promise.all(attachmentUpload);
|
||||
}
|
||||
|
||||
return res.data;
|
||||
}
|
||||
|
||||
async function deleteByIdCheckUp(
|
||||
opts: {
|
||||
employeeId: string;
|
||||
checkUpId?: string;
|
||||
},
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
async function deleteByIdCheckUp(opts: {
|
||||
employeeId: string;
|
||||
checkUpId?: string;
|
||||
}) {
|
||||
const res = await api.delete<Employee>(
|
||||
`/employee/${opts.employeeId}/checkup/${opts.checkUpId}`,
|
||||
{
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
},
|
||||
{ headers: { 'X-Rtid': flowStore.rtid } },
|
||||
);
|
||||
|
||||
if (!res) return false;
|
||||
|
|
@ -355,25 +279,11 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
return false;
|
||||
}
|
||||
|
||||
async function deleteByIdWork(
|
||||
opts: {
|
||||
employeeId: string;
|
||||
workId?: string;
|
||||
},
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
async function deleteByIdWork(opts: { employeeId: string; workId?: string }) {
|
||||
const res = await api.delete<Employee>(
|
||||
`/employee/${opts.employeeId}/work/${opts.workId}`,
|
||||
{
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
headers: { 'X-Rtid': flowStore.rtid },
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -383,20 +293,9 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
return false;
|
||||
}
|
||||
|
||||
async function deleteById(
|
||||
id: string,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
async function deleteById(id: string) {
|
||||
const res = await api.delete<Employee>(`/employee/${id}`, {
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
headers: { 'X-Rtid': flowStore.rtid },
|
||||
});
|
||||
|
||||
if (!res) return false;
|
||||
|
|
@ -405,82 +304,38 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
return false;
|
||||
}
|
||||
|
||||
async function fetchCheckup(
|
||||
id: string,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
async function fetchCheckup(id: string) {
|
||||
const res = await api.get<EmployeeCheckup[]>(`/employee/${id}/checkup`, {
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
headers: { 'X-Rtid': flowStore.rtid },
|
||||
});
|
||||
if (res && res.status === 200) {
|
||||
return res.data;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchWork(
|
||||
id: string,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
async function fetchWork(id: string) {
|
||||
const res = await api.get<EmployeeWork[]>(`/employee/${id}/work`, {
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
headers: { 'X-Rtid': flowStore.rtid },
|
||||
});
|
||||
if (res && res.status === 200) {
|
||||
return res.data;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchOther(
|
||||
id: string,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
async function fetchOther(id: string) {
|
||||
const res = await api.get<EmployeeOther>(`/employee/${id}/other-info`, {
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
headers: { 'X-Rtid': flowStore.rtid },
|
||||
});
|
||||
if (res && res.status === 200) {
|
||||
return res.data;
|
||||
}
|
||||
}
|
||||
|
||||
async function getStatsEmployee(
|
||||
customerBranchId?: string,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
async function getStatsEmployee(customerBranchId?: string) {
|
||||
const res = await api.get(
|
||||
`/employee/stats${customerBranchId ? '?customerBranchId=' + customerBranchId : ''}/`,
|
||||
{
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
headers: { 'X-Rtid': flowStore.rtid },
|
||||
},
|
||||
);
|
||||
if (res && res.status === 200) {
|
||||
|
|
@ -488,19 +343,11 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
}
|
||||
}
|
||||
|
||||
async function getStatsEmployeeGender(
|
||||
opts?: {
|
||||
customerBranchId?: string;
|
||||
status?: 'CREATED' | 'ACTIVE' | 'INACTIVE';
|
||||
query?: string;
|
||||
},
|
||||
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
async function getStatsEmployeeGender(opts?: {
|
||||
customerBranchId?: string;
|
||||
status?: 'CREATED' | 'ACTIVE' | 'INACTIVE';
|
||||
query?: string;
|
||||
}) {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
for (const [k, v] of Object.entries(opts || {})) {
|
||||
|
|
@ -512,11 +359,7 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
const res = await api.get(
|
||||
`/employee/stats/gender${(params && '?'.concat(query)) || ''}`,
|
||||
{
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
headers: { 'X-Rtid': flowStore.rtid },
|
||||
},
|
||||
);
|
||||
if (res && res.status === 200) {
|
||||
|
|
@ -524,26 +367,66 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
}
|
||||
}
|
||||
|
||||
async function getEditHistory(
|
||||
employeeId: string,
|
||||
flow?: {
|
||||
sessionId?: string;
|
||||
refTransactionId?: string;
|
||||
transactionId?: string;
|
||||
},
|
||||
) {
|
||||
async function getEditHistory(employeeId: string) {
|
||||
const res = await api.get(`/employee/${employeeId}/edit-history`, {
|
||||
headers: {
|
||||
'X-Session-Id': flow?.sessionId,
|
||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
||||
'X-Tid': flow?.transactionId,
|
||||
},
|
||||
headers: { 'X-Rtid': flowStore.rtid },
|
||||
});
|
||||
if (res && res.status === 200) {
|
||||
return res.data;
|
||||
}
|
||||
}
|
||||
|
||||
async function listAttachment(employeeId: string) {
|
||||
const res = await api.get<string[]>(`/employee/${employeeId}/attachment`);
|
||||
return !res || res.status >= 400 ? false : res.data;
|
||||
}
|
||||
async function getAttachment(
|
||||
employeeId: string,
|
||||
filename: string,
|
||||
download = false,
|
||||
) {
|
||||
const url = `${baseUrl}/employee/${employeeId}/attachment/${filename}`;
|
||||
const res = await api.get<string>(url);
|
||||
|
||||
if (download) {
|
||||
fetch(res.data)
|
||||
.then(async (res) => await res.blob())
|
||||
.then((blob) => {
|
||||
let a = document.createElement('a');
|
||||
a.download = filename;
|
||||
a.href = window.URL.createObjectURL(blob);
|
||||
a.click();
|
||||
a.remove();
|
||||
});
|
||||
}
|
||||
|
||||
return res.data;
|
||||
}
|
||||
async function uploadAttachment(
|
||||
employeeId: string,
|
||||
file: File,
|
||||
filename?: string,
|
||||
) {
|
||||
const res = await api.put(
|
||||
`/employee/${employeeId}/attachment/${filename || file.name}`,
|
||||
file,
|
||||
{
|
||||
headers: {
|
||||
'X-Rtid': flowStore.rtid,
|
||||
'Content-Type': file.type,
|
||||
},
|
||||
},
|
||||
);
|
||||
return !(!res || res.status >= 400);
|
||||
}
|
||||
async function deleteAttachment(employeeId: string, filename: string) {
|
||||
const res = await api.delete(
|
||||
`/employee/${employeeId}/attachment/${filename}`,
|
||||
{ headers: { 'X-Rtid': flowStore.rtid } },
|
||||
);
|
||||
return !(!res || res.status >= 400);
|
||||
}
|
||||
|
||||
return {
|
||||
data,
|
||||
globalOption,
|
||||
|
|
@ -571,6 +454,11 @@ const useEmployeeStore = defineStore('api-employee', () => {
|
|||
|
||||
createEmployeeOtherInfo,
|
||||
editByIdEmployeeOtherInfo,
|
||||
|
||||
listAttachment,
|
||||
getAttachment,
|
||||
uploadAttachment,
|
||||
deleteAttachment,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export type Employee = {
|
|||
createdByUserId: string;
|
||||
updatedByUserId: string;
|
||||
statusOrder: string;
|
||||
namePrefix: string;
|
||||
firstName: string;
|
||||
firstNameEN: string;
|
||||
lastName: string;
|
||||
|
|
@ -107,6 +108,13 @@ export type EmployeeCreate = {
|
|||
employeeCheckup?: EmployeeCheckupCreate[];
|
||||
|
||||
employeeOtherInfo?: EmployeeOtherCreate;
|
||||
|
||||
file?: {
|
||||
name?: string;
|
||||
group?: string;
|
||||
url?: string;
|
||||
file?: File;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type EmployeeUpdate = {
|
||||
|
|
|
|||
|
|
@ -18,12 +18,19 @@ const useOcr = defineStore('useOcrStore', () => {
|
|||
},
|
||||
) {
|
||||
const res = await axios
|
||||
.post(`${baseUrl}/`, payload.file, {
|
||||
.post<{
|
||||
document: string;
|
||||
fields: { name: string; value: string }[];
|
||||
result: string;
|
||||
}>(`${baseUrl}/`, payload.file, {
|
||||
headers: { 'Content-Type': payload.file?.type },
|
||||
onUploadProgress: (e) => console.log(e),
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
// ]);
|
||||
|
||||
if (!res || res.status >= 400) return false;
|
||||
|
||||
return res.data;
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue