feat: employee history dialog & table
This commit is contained in:
parent
39272000a7
commit
3458517de4
3 changed files with 349 additions and 50 deletions
|
|
@ -1,14 +1,24 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { QTableColumn } from 'quasar';
|
import { QTableColumn } from 'quasar';
|
||||||
|
import { EmployeeHistory, NewEmployeeHistory } from 'src/stores/employee/types';
|
||||||
|
import { dateFormat } from 'src/utils/datetime';
|
||||||
|
import NoData from '../NoData.vue';
|
||||||
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
|
import useOptionStore from 'src/stores/options';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const optionStore = useOptionStore();
|
||||||
|
|
||||||
|
const historyList = defineModel<EmployeeHistory[]>('historyList', {
|
||||||
|
required: true,
|
||||||
|
});
|
||||||
|
|
||||||
const columns: QTableColumn[] = [
|
const columns: QTableColumn[] = [
|
||||||
{
|
{
|
||||||
name: 'time',
|
name: 'updatedAt',
|
||||||
label: t('time'),
|
label: t('time'),
|
||||||
field: 'time',
|
field: 'updatedAt',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
headerStyle: 'font-weight: bold',
|
headerStyle: 'font-weight: bold',
|
||||||
},
|
},
|
||||||
|
|
@ -42,25 +52,254 @@ const columns: QTableColumn[] = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const rows = [
|
const currentDate = ref();
|
||||||
|
const currentData = ref();
|
||||||
|
const currentIndex = ref(0);
|
||||||
|
const formatList = ref<NewEmployeeHistory[]>([]);
|
||||||
|
|
||||||
|
const fieldName = [
|
||||||
{
|
{
|
||||||
time: '17:00:29',
|
name: 'customerBranchId',
|
||||||
editBy: 'สุขใจ แสนดี',
|
title: 'formDialogTitleInformation',
|
||||||
history: [
|
i18n: 'formDialogEmployerID',
|
||||||
{ title: 'ข้อมูลส่วนตัว', caption: 'อัพโหลดรูปภาพ' },
|
|
||||||
{ title: 'ข้อมูลผลตรวจสุขภาพ', caption: 'ผลตรวจสุขภาพ' },
|
|
||||||
],
|
|
||||||
valueBefore: [{ title: 'ผิดปกติ' }, { title: 'ผิดปกติ' }],
|
|
||||||
valueAfter: [{ title: 'ปกติ' }, { title: 'ปกติ' }],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
time: '15:20:01',
|
name: 'nrcNo',
|
||||||
editBy: 'สุขใจ แสนดี',
|
title: 'formDialogTitleInformation',
|
||||||
history: [{ title: 'ข้อมูลส่วนตัว', caption: 'อัพโหลดรูปภาพ' }],
|
i18n: 'formDialogEmployeeNRCNo',
|
||||||
valueBefore: [{ title: '-' }],
|
},
|
||||||
valueAfter: [{ title: '1.jpg' }],
|
|
||||||
|
{
|
||||||
|
name: 'firstName',
|
||||||
|
title: 'personalInfo',
|
||||||
|
i18n: 'formDialogInputFirstName',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'firstNameEN',
|
||||||
|
title: 'personalInfo',
|
||||||
|
i18n: 'formDialogInputFirstNameEN',
|
||||||
|
},
|
||||||
|
{ name: 'lastName', title: 'personalInfo', i18n: 'formDialogInputLastName' },
|
||||||
|
{
|
||||||
|
name: 'lastNameEN',
|
||||||
|
title: 'personalInfo',
|
||||||
|
i18n: 'formDialogInputLastNameEN',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'dateOfBirth',
|
||||||
|
title: 'personalInfo',
|
||||||
|
i18n: 'formDialogInputBirthDate',
|
||||||
|
},
|
||||||
|
{ name: 'gender', title: 'personalInfo', i18n: 'formDialogInputGender' },
|
||||||
|
{
|
||||||
|
name: 'nationality',
|
||||||
|
title: 'personalInfo',
|
||||||
|
i18n: 'formDialogInputNationality',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'address',
|
||||||
|
title: 'formDialogTitlePersonnelAddress',
|
||||||
|
i18n: 'formDialogTitleAddressPure',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'addressEN',
|
||||||
|
title: 'formDialogTitlePersonnelAddress',
|
||||||
|
i18n: 'formDialogTitleAddressPureEN',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'provinceId',
|
||||||
|
title: 'formDialogTitlePersonnelAddress',
|
||||||
|
i18n: 'province',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'districtId',
|
||||||
|
title: 'formDialogTitlePersonnelAddress',
|
||||||
|
i18n: 'district',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'subDistrictId',
|
||||||
|
title: 'formDialogTitlePersonnelAddress',
|
||||||
|
i18n: 'subDistrict',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'passportType',
|
||||||
|
title: 'formDialogTitlePassport',
|
||||||
|
i18n: 'formDialogInputPassportType',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'passportNumber',
|
||||||
|
title: 'formDialogTitlePassport',
|
||||||
|
i18n: 'formDialogInputPassportNo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'previousPassportReference',
|
||||||
|
title: 'formDialogTitlePassport',
|
||||||
|
i18n: 'formDialogInputPassportRef',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'passportIssuingPlace',
|
||||||
|
title: 'formDialogTitlePassport',
|
||||||
|
i18n: 'formDialogInputWPassportPlace',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'passportIssuingCountry',
|
||||||
|
title: 'formDialogTitlePassport',
|
||||||
|
i18n: 'formDialogInputPassportCountry',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'passportIssueDate',
|
||||||
|
title: 'formDialogTitlePassport',
|
||||||
|
i18n: 'formDialogInputPassportIssuance',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'passportExpiryDate',
|
||||||
|
title: 'formDialogTitlePassport',
|
||||||
|
i18n: 'formDialogInputPassportExpire',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'visaType',
|
||||||
|
title: 'formDialogTitleVisa',
|
||||||
|
i18n: 'formDialogInputVisaType',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'visaNumber',
|
||||||
|
title: 'formDialogTitleVisa',
|
||||||
|
i18n: 'formDialogInputVisaNo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'visaIssueDate',
|
||||||
|
title: 'formDialogTitleVisa',
|
||||||
|
i18n: 'formDialogInputVisaIssuance',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'visaExpiryDate',
|
||||||
|
title: 'formDialogTitleVisa',
|
||||||
|
i18n: 'formDialogInputVisaExpire',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'visaIssuingPlace',
|
||||||
|
title: 'formDialogTitleVisa',
|
||||||
|
i18n: 'formDialogInputVisaPlace',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'visaStayUntilDate',
|
||||||
|
title: 'formDialogTitleVisa',
|
||||||
|
i18n: 'formDialogInputVisaStayUntil',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tm6Number',
|
||||||
|
title: 'formDialogTitleVisa',
|
||||||
|
i18n: 'formDialogInputVisaTM6',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'entryDate',
|
||||||
|
title: 'formDialogTitleVisa',
|
||||||
|
i18n: 'formDialogInputVisaEnter',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function isValidDate(dateString: string): boolean {
|
||||||
|
if (typeof dateString !== 'string' || dateString.length < 24) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const date = new Date(dateString);
|
||||||
|
|
||||||
|
return !isNaN(date.getTime()) && dateString === date.toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapName(field: string): { title: string; i18n: string } {
|
||||||
|
const fieldData = fieldName.find((item) => item.name === field);
|
||||||
|
if (fieldData) {
|
||||||
|
return { title: fieldData.title, i18n: fieldData.i18n };
|
||||||
|
}
|
||||||
|
return { title: '-', i18n: '-' };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function groupEmployeeHistory(
|
||||||
|
historyList: EmployeeHistory[],
|
||||||
|
): Promise<NewEmployeeHistory[]> {
|
||||||
|
const grouped = historyList.reduce((acc, curr) => {
|
||||||
|
const updatedAt = new Date(curr.updatedAt);
|
||||||
|
const dateKey = `${updatedAt.getFullYear()}-${updatedAt.getMonth() + 1}-${updatedAt.getDate()}`;
|
||||||
|
|
||||||
|
const existingEntry = acc.find((entry) => entry.date === dateKey);
|
||||||
|
|
||||||
|
if (existingEntry) {
|
||||||
|
const existingData = existingEntry.data.find(
|
||||||
|
(data) => data.updatedAt.getTime() === updatedAt.getTime(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingData) {
|
||||||
|
existingData.history.push({
|
||||||
|
valueAfter: curr.valueAfter,
|
||||||
|
valueBefore: curr.valueBefore,
|
||||||
|
field: curr.field,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
existingEntry.data.push({
|
||||||
|
masterId: curr.masterId,
|
||||||
|
updatedBy: curr.updatedBy,
|
||||||
|
updatedByUserId: curr.updatedByUserId,
|
||||||
|
timestamp: curr.timestamp,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
id: curr.id,
|
||||||
|
history: [
|
||||||
|
{
|
||||||
|
valueAfter: curr.valueAfter,
|
||||||
|
valueBefore: curr.valueBefore,
|
||||||
|
field: curr.field,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
acc.push({
|
||||||
|
date: dateKey,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
masterId: curr.masterId,
|
||||||
|
updatedBy: curr.updatedBy,
|
||||||
|
updatedByUserId: curr.updatedByUserId,
|
||||||
|
timestamp: curr.timestamp,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
id: curr.id,
|
||||||
|
history: [
|
||||||
|
{
|
||||||
|
valueAfter: curr.valueAfter,
|
||||||
|
valueBefore: curr.valueBefore,
|
||||||
|
field: curr.field,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, [] as NewEmployeeHistory[]);
|
||||||
|
|
||||||
|
return grouped;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const newList = await groupEmployeeHistory(historyList.value);
|
||||||
|
formatList.value = newList;
|
||||||
|
|
||||||
|
currentDate.value = formatList.value[currentIndex.value].date;
|
||||||
|
currentData.value = formatList.value[currentIndex.value].data;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => currentIndex.value,
|
||||||
|
(i) => {
|
||||||
|
currentDate.value = formatList.value[i].date;
|
||||||
|
currentData.value = formatList.value[i].data;
|
||||||
|
},
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -70,41 +309,57 @@ const rows = [
|
||||||
style="background: hsla(var(--info-bg) / 0.1)"
|
style="background: hsla(var(--info-bg) / 0.1)"
|
||||||
>
|
>
|
||||||
<div class="surface-1 q-py-sm q-px-sm row items-center">
|
<div class="surface-1 q-py-sm q-px-sm row items-center">
|
||||||
<q-btn flat padding="0" icon="mdi-chevron-left" />
|
<q-btn
|
||||||
|
flat
|
||||||
|
:disable="currentIndex === formatList.length - 1"
|
||||||
|
color="info"
|
||||||
|
padding="0"
|
||||||
|
icon="mdi-chevron-left"
|
||||||
|
@click="currentIndex++"
|
||||||
|
/>
|
||||||
<span class="text-weight-medium q-px-xl">
|
<span class="text-weight-medium q-px-xl">
|
||||||
{{ '20 มีนาคม 2567' }}
|
{{ dateFormat(currentDate) }}
|
||||||
</span>
|
</span>
|
||||||
<q-btn flat padding="0" icon="mdi-chevron-right" />
|
<q-btn
|
||||||
|
flat
|
||||||
|
:disable="currentIndex === 0"
|
||||||
|
color="info"
|
||||||
|
padding="0"
|
||||||
|
icon="mdi-chevron-right"
|
||||||
|
@click="currentIndex--"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-table
|
<q-table
|
||||||
|
v-if="currentData?.length > 0"
|
||||||
flat
|
flat
|
||||||
class="table-border"
|
class="table-border"
|
||||||
table-header-class="surface-2"
|
table-header-class="surface-2"
|
||||||
:rows="rows"
|
:rows="currentData"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
row-key="name"
|
row-key="name"
|
||||||
>
|
>
|
||||||
<template v-slot:body="props">
|
<template v-slot:body="props">
|
||||||
<q-tr
|
<q-tr
|
||||||
:props="props"
|
:props="props"
|
||||||
:style="`background-color: ${props.rowIndex / 2 === 0 ? '' : 'var(--surface-2)'}`"
|
:style="`background-color: ${props.rowIndex % 2 === 0 ? '' : 'var(--surface-2)'}`"
|
||||||
>
|
>
|
||||||
<q-td key="time" :props="props">
|
<q-td key="updatedAt" :props="props">
|
||||||
{{ props.row.time }}
|
{{ dateFormat(props.row.updatedAt, false, true, true) }}
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
||||||
<q-td key="editBy" :props="props">
|
<q-td key="editBy" :props="props">
|
||||||
<div class="row items-center no-wrap">
|
<div class="row items-center no-wrap">
|
||||||
<q-avatar>
|
<q-avatar class="surface-tab">
|
||||||
<img src="https://cdn.quasar.dev/img/avatar.png" />
|
<img v-if="false" src="https://cdn.quasar.dev/img/avatar.png" />
|
||||||
|
<q-icon v-else name="mdi-account"></q-icon>
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
<div class="column q-pl-md items-start">
|
<div class="column q-pl-md items-start">
|
||||||
<span class="text-weight-bold">
|
<span class="text-weight-bold">
|
||||||
{{ props.row.editBy }}
|
{{ props.row.editBy ?? '-' }}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-caption">นักบริหาร</span>
|
<!-- <span class="text-caption">นักบริหาร</span> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
@ -112,38 +367,51 @@ const rows = [
|
||||||
<q-td key="history" :props="props">
|
<q-td key="history" :props="props">
|
||||||
<q-stepper vertical flat>
|
<q-stepper vertical flat>
|
||||||
<q-step
|
<q-step
|
||||||
v-for="(item, index) in props.row.history.slice().reverse()"
|
v-for="(item, index) in props.row.history"
|
||||||
:key="index"
|
:key="index"
|
||||||
:name="1"
|
:name="1"
|
||||||
:title="item.title"
|
:title="$t(mapName(item.field).title)"
|
||||||
:caption="item.caption"
|
:caption="$t(mapName(item.field).i18n)"
|
||||||
:icon="`mdi-numeric-${props.row.history.length - index}`"
|
:icon="`mdi-numeric-${props.row.history.length - index}`"
|
||||||
/>
|
>
|
||||||
|
asd
|
||||||
|
</q-step>
|
||||||
</q-stepper>
|
</q-stepper>
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
||||||
<q-td key="valueBefore" :props="props">
|
<q-td key="valueBefore" :props="props">
|
||||||
<div
|
<div
|
||||||
v-for="(item, index) in props.row.valueBefore.slice().reverse()"
|
v-for="(i, index) in props.row.history"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="q-py-md"
|
class="q-py-md"
|
||||||
>
|
>
|
||||||
{{ item.title }}
|
{{
|
||||||
|
isValidDate(i.valueBefore) === true
|
||||||
|
? dateFormat(i.valueBefore)
|
||||||
|
: optionStore.mapOption(i.valueBefore)
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
||||||
<q-td key="valueAfter" :props="props">
|
<q-td key="valueAfter" :props="props">
|
||||||
<div
|
<div
|
||||||
v-for="(item, index) in props.row.valueAfter.slice().reverse()"
|
v-for="(i, index) in props.row.history"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="q-py-md"
|
class="q-py-md"
|
||||||
>
|
>
|
||||||
{{ item.title }}
|
{{
|
||||||
|
isValidDate(i.valueAfter) === true
|
||||||
|
? dateFormat(i.valueAfter)
|
||||||
|
: optionStore.mapOption(i.valueAfter)
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
</q-td>
|
</q-td>
|
||||||
</q-tr>
|
</q-tr>
|
||||||
</template>
|
</template>
|
||||||
</q-table>
|
</q-table>
|
||||||
|
<div v-else class="table-border flex items-center justify-center q-py-lg">
|
||||||
|
<NoData />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,22 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, ref, watch } from 'vue';
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
import SignaturePad from 'signature_pad';
|
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
|
import SignaturePad from 'signature_pad';
|
||||||
|
import Cropper from 'cropperjs';
|
||||||
|
|
||||||
defineExpose({ clearCanvas, clearUpload });
|
defineExpose({ clearCanvas, clearUpload });
|
||||||
|
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
|
const isDarkActive = computed(() => $q.dark.isActive);
|
||||||
|
|
||||||
const canvasRef = ref<HTMLCanvasElement>();
|
const canvasRef = ref<HTMLCanvasElement>();
|
||||||
const signaturePad = ref();
|
const signaturePad = ref();
|
||||||
const currentColor = ref('blue');
|
const currentColor = ref('blue');
|
||||||
|
|
||||||
|
const imageRef = ref<HTMLImageElement>();
|
||||||
|
const cropper = ref();
|
||||||
|
|
||||||
const tab = ref('draw');
|
const tab = ref('draw');
|
||||||
|
|
||||||
const isDarkActive = computed(() => $q.dark.isActive);
|
|
||||||
|
|
||||||
const uploadFile = ref<File | undefined>(undefined);
|
const uploadFile = ref<File | undefined>(undefined);
|
||||||
const profileUrl = ref<string | null>('');
|
const profileUrl = ref<string | null>('');
|
||||||
const inputFile = (() => {
|
const inputFile = (() => {
|
||||||
|
|
@ -36,7 +39,7 @@ const inputFile = (() => {
|
||||||
return element;
|
return element;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function initializeSignaturePad(canva?: HTMLCanvasElement) {
|
async function initializeSignaturePad(canva?: HTMLCanvasElement) {
|
||||||
if (canva) {
|
if (canva) {
|
||||||
signaturePad.value = new SignaturePad(canva, {
|
signaturePad.value = new SignaturePad(canva, {
|
||||||
backgroundColor: isDarkActive.value
|
backgroundColor: isDarkActive.value
|
||||||
|
|
@ -49,6 +52,26 @@ function initializeSignaturePad(canva?: HTMLCanvasElement) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function initializeCropper(image?: HTMLImageElement) {
|
||||||
|
console.log(image);
|
||||||
|
if (image) {
|
||||||
|
cropper.value = new Cropper(image, {
|
||||||
|
aspectRatio: 16 / 9,
|
||||||
|
crop(event) {
|
||||||
|
console.log(event.detail.x);
|
||||||
|
console.log(event.detail.y);
|
||||||
|
console.log(event.detail.width);
|
||||||
|
console.log(event.detail.height);
|
||||||
|
console.log(event.detail.rotate);
|
||||||
|
console.log(event.detail.scaleX);
|
||||||
|
console.log(event.detail.scaleY);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.warn('Canvas reference not found. Cropper not initialized.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function changeColor(color: string) {
|
function changeColor(color: string) {
|
||||||
signaturePad.value.penColor = color;
|
signaturePad.value.penColor = color;
|
||||||
currentColor.value = color;
|
currentColor.value = color;
|
||||||
|
|
@ -65,12 +88,14 @@ function clearUpload() {
|
||||||
watch(
|
watch(
|
||||||
() => tab.value,
|
() => tab.value,
|
||||||
async () => {
|
async () => {
|
||||||
initializeSignaturePad(canvasRef.value);
|
await initializeSignaturePad(canvasRef.value);
|
||||||
|
await initializeCropper(imageRef.value);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
initializeSignaturePad(canvasRef.value);
|
await initializeSignaturePad(canvasRef.value);
|
||||||
|
await initializeCropper(imageRef.value);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -161,17 +186,18 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="tab === 'upload'" class="q-pa-md">
|
<div v-show="tab === 'upload'" class="q-pa-md">
|
||||||
<div
|
<div
|
||||||
class="bordered upload-border rounded column items-center justify-center"
|
class="bordered upload-border rounded column items-center justify-center"
|
||||||
style="height: 312px"
|
style="height: 312px"
|
||||||
>
|
>
|
||||||
<q-img
|
<q-img
|
||||||
v-if="profileUrl"
|
v-show="profileUrl"
|
||||||
:src="profileUrl"
|
ref="imageRef"
|
||||||
|
:src="profileUrl ?? ''"
|
||||||
style="object-fit: cover; width: 100%; height: 100%"
|
style="object-fit: cover; width: 100%; height: 100%"
|
||||||
/>
|
/>
|
||||||
<div v-else>
|
<div v-if="!profileUrl">
|
||||||
<q-icon
|
<q-icon
|
||||||
name="mdi-cloud-upload"
|
name="mdi-cloud-upload"
|
||||||
size="10rem"
|
size="10rem"
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ import {
|
||||||
Employee,
|
Employee,
|
||||||
EmployeeWork,
|
EmployeeWork,
|
||||||
EmployeeCheckup,
|
EmployeeCheckup,
|
||||||
|
EmployeeHistory,
|
||||||
} from 'stores/employee/types';
|
} from 'stores/employee/types';
|
||||||
import { onMounted } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
|
|
||||||
|
|
@ -113,7 +114,6 @@ const formData = ref<CustomerCreate>({
|
||||||
image: null,
|
image: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const employeeHistoryDialog = ref(false);
|
|
||||||
const inputSearch = ref<string>();
|
const inputSearch = ref<string>();
|
||||||
const fieldSelectedCustomer = ref<{ label: string; value: string }>({
|
const fieldSelectedCustomer = ref<{ label: string; value: string }>({
|
||||||
label: t('all'),
|
label: t('all'),
|
||||||
|
|
@ -363,6 +363,9 @@ const selectorList = computed(() => [
|
||||||
|
|
||||||
const customerType = ref<CustomerType>('CORP');
|
const customerType = ref<CustomerType>('CORP');
|
||||||
|
|
||||||
|
const employeeHistoryDialog = ref(false);
|
||||||
|
const employeeHistory = ref<EmployeeHistory[]>();
|
||||||
|
|
||||||
function triggerCreate(type: CustomerType) {
|
function triggerCreate(type: CustomerType) {
|
||||||
customerType.value = type;
|
customerType.value = type;
|
||||||
openDialogInputForm();
|
openDialogInputForm();
|
||||||
|
|
@ -1072,7 +1075,8 @@ async function checkEmployeeForm() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openHistory(id: string) {
|
async function openHistory(id: string) {
|
||||||
console.log(id);
|
const res = await employeeStore.getEditHistory(id);
|
||||||
|
employeeHistory.value = res.reverse();
|
||||||
employeeHistoryDialog.value = true;
|
employeeHistoryDialog.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2883,8 +2887,9 @@ watch([inputSearch, currentStatus], async () => {
|
||||||
:title="$t('editHistory')"
|
:title="$t('editHistory')"
|
||||||
v-model:modal="employeeHistoryDialog"
|
v-model:modal="employeeHistoryDialog"
|
||||||
:close="() => (employeeHistoryDialog = false)"
|
:close="() => (employeeHistoryDialog = false)"
|
||||||
|
v-if="employeeHistory"
|
||||||
>
|
>
|
||||||
<HistoryEditComponent />
|
<HistoryEditComponent v-model:history-list="employeeHistory" />
|
||||||
</FormDialog>
|
</FormDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue