hrms-mgt/src/modules/04_registryNew/views/detailView.vue
2024-05-28 13:09:12 +07:00

1008 lines
26 KiB
Vue

<script setup lang="ts">
import { ref, onMounted, reactive } from "vue";
import axios from "axios";
import { useRoute, useRouter } from "vue-router";
import { useCounterMixin } from "@/stores/mixin";
import http from "@/plugins/http";
import config from "@/app.config";
import { useQuasar } from "quasar";
import type { DataOption } from "@/modules/04_registryNew/interface/index/Main";
import type { DataPerson } from "@/modules/04_registryNew/interface/response/Main";
import avatar from "@/assets/avatar_user.jpg";
import TabMain from "@/modules/04_registryNew/components/detail/TabMain.vue";
import UploadFile from "@/modules/11_discipline/components/UploadFile.vue";
import type { ResponseObject } from "@/modules/04_registryNew/interface/response/Profile";
import DialogHeader from "@/components/DialogHeader.vue";
/** ถึงเเก่กรรม */
const dialogPassaway = ref<boolean>(false);
const placeDeathCertificate = ref("");
const deathCertificateNo = ref("");
const dateDeath = ref<Date>(new Date());
const filePassaway = ref<any>(null);
const reasonDeath = ref("");
const dialogImage = ref<boolean>(false);
const mixin = useCounterMixin();
const $q = useQuasar();
const router = useRouter();
const route = useRoute();
const {
dialogRemove,
dialogConfirm,
showLoader,
hideLoader,
messageError,
success,
date2Thai,
dateToISO,
dialogMessageNotify,
} = mixin;
const profileId = ref<string>(route.params.id.toString());
const empType = ref<string>(
route.name === "registryNewByid" ? "" : "-employee"
);
const formDetail = ref<ResponseObject>();
const itemsMenu = ref<DataOption[]>([
{
id: "1",
name: "ช่วยราชการ",
},
{
id: "2",
name: "ส่งตัวกลับ",
},
{
id: "3",
name: "แต่งตั้ง-เลื่อน-ย้าย",
},
{
id: "4",
name: "ถึงแก่กรรม",
},
{
id: "5",
name: "ให้ออกจากราชการ",
},
{
id: "6",
name: "อื่นๆ",
},
]);
const itemsMenuEmployee = ref<DataOption[]>([
{
id: "1",
name: "ปรับระดับชั้นงาน - ย้าย",
},
{
id: "2",
name: "ถึงแก่กรรม",
},
]);
const uploadUrl = ref<string>("");
const fileName = ref<string>("");
const profilePicture = ref<string>("");
const profileFile = ref();
const input = document.createElement("input");
const activeImage = ref<any | null>(null);
const images = ref<any[]>([]);
const imagesAlldata = ref<any[]>([]);
input.type = "file";
input.accept = ".jpg,.png,.tif,.pic";
input.addEventListener("change", (e) => {
profileFile.value = (e.currentTarget as HTMLInputElement).files?.[0];
uploadImg();
});
function selectFile() {
input.click();
imageActive(null);
}
function imageActive(n: any) {
activeImage.value = n;
}
function uploadImg() {
http
.post(config.API.orgProfileAvatar, {
profileId: profileId.value,
})
.then((res) => {
console.log(res.data);
fileName.value = res.data.result.avatarName;
uploadProfile(res.data.result.avatar);
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {});
}
async function uploadProfile(path: string) {
await http
.post(config.API.fileByPath(path), {
replace: true,
fileList: [
{
fileName: fileName.value,
},
],
})
.then(async (res) => {
uploadUrl.value = res.data[fileName.value].uploadUrl;
uploadFileURL(uploadUrl.value, profileFile.value);
closeImage();
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
async function uploadFileURL(uploadUrl: string, file: any) {
showLoader();
await axios
.put(uploadUrl, file, {
headers: {
"Content-Type": file.type,
},
})
.then(() => {
fetchProfile(profileId.value);
success($q, "อัปโหลดไฟล์สำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
async function fetchProfile(id: string) {
showLoader();
await http
.get(config.API.fileByFile("ทะเบียนประวัติ", "โปรไฟล์", id, fileName.value))
.then(async (res) => {
profilePicture.value = res.data.downloadUrl;
})
.catch(() => {
profilePicture.value = avatar;
})
.finally(() => {
hideLoader();
});
}
const reasonStatus = ref<boolean>(false);
const leaveReason = ref<string>("");
const reasonOptions = ref<DataOption[]>([
{
id: "RETIRE",
name: "เกษียณอายุราชการ",
},
{
id: "RESIGN",
name: "ลาออก",
},
{
id: "TRANSFER",
name: "ให้โอน",
},
{
id: "DEATH",
name: "ถึงแก่กรรม",
},
{
id: "LAYOFF",
name: "ให้ออก",
},
{
id: "DISCHARGE",
name: "ปลดออก",
},
{
id: "DISMISS",
name: "ไล่ออก",
},
{
id: "OTHER",
name: "อื่นๆ",
},
]);
async function fetchDataPersonal() {
showLoader();
await http
.get(config.API.registryNewByProfileId(profileId.value, empType.value))
.then((res) => {
formDetail.value = res.data.result;
if (res.data.result.leaveReason) {
// เหตุผลพ้นจากราชการต่อท้ายชื่อ
const reason = reasonOptions.value.filter(
(r: DataOption) => r.id == res.data.result.leaveReason
);
if (reason.length > 0) {
leaveReason.value = ` (พ้นจากราชการด้วยสาเหตุ: ${reason[0].name})`;
} else if (
res.data.result.leaveReason !== null &&
res.data.result.leaveReason !== ""
) {
leaveReason.value = ` (พ้นจากราชการด้วยสาเหตุ: ${res.data.result.leaveReason})`;
}
reasonStatus.value = reason.length > 0 ? true : false;
}
fileName.value = res.data.result.avatarName;
if (formDetail.value?.avatarName) {
fetchProfile(profileId.value);
} else {
profilePicture.value = avatar;
}
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
function onClickDownloadKp7(type: string) {
showLoader();
const url =
type === "FULL"
? config.API.profileReportId(profileId.value)
: config.API.profileKp7ShortId(profileId.value);
const fileName = type === "FULL" ? "ก.พ.7/ก.ก.1" : "ประวัติแบบย่อ";
http
.get(url, {
responseType: "arraybuffer", //
})
.then((res) => {
const data = res.data;
console.log(data);
const blob = new Blob([data], { type: "application/pdf" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = `${fileName}.pdf`;
document.body.appendChild(link);
link.click();
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** ช่วยราชการ */
async function helpPost() {
const formData = new FormData();
formData.append("id", profileId.value);
dialogConfirm($q, async () => {
showLoader();
await http
.post(config.API.placemenHelpGov, formData)
.then(() => {
success($q, "ดำเนินการสำเร็จ");
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
router.push("/help-government");
});
});
}
/** ส่งตัวกลับ */
async function repatriationPost() {
const formData = new FormData();
formData.append("id", profileId.value);
dialogConfirm($q, async () => {
showLoader();
await http
.post(config.API.placemenRepatriation, formData)
.then(() => {
success($q, "ดำเนินการสำเร็จ");
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
router.push("/repatriate");
});
});
}
/** แต่งตังเลื่อน */
async function appointPost() {
const formData = new FormData();
formData.append("id", profileId.value);
dialogConfirm($q, async () => {
showLoader();
await http
.post(config.API.placemenAppointment, formData)
.then(() => {
success($q, "ดำเนินการสำเร็จ");
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
router.push("/appoint-promote");
});
});
}
/** ถึงเเก่กรรม */
async function clickPassaway() {
dialogPassaway.value = true;
}
/** ให้ออกจากราชการ */
async function outPost() {
const formData = new FormData();
formData.append("id", profileId.value);
dialogConfirm($q, async () => {
showLoader();
await http
.post(config.API.retirementOut, formData)
.then(() => {
success($q, "ดำเนินการสำเร็จ");
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
router.push("/dismiss-order");
});
});
}
/** อื่นๆ */
async function otherPost() {
const formData = new FormData();
formData.append("id", profileId.value);
dialogConfirm($q, async () => {
showLoader();
await http
.post(config.API.placemenOther, formData)
.then(() => {
success($q, "ดำเนินการสำเร็จ");
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
router.push("/other");
});
});
}
const appointEmployeePost = async () => {
const formData = new FormData();
formData.append("id", profileId.value);
dialogConfirm($q, async () => {
showLoader();
await http
.post(config.API.appointEmployee(), formData)
.then(() => {
success($q, "ดำเนินการสำเร็จ");
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
router.push("/appoint-employee");
});
});
};
function closePassaway() {
dialogPassaway.value = false;
}
async function clickSaveDeceased() {
const formData = new FormData();
formData.append("File", filePassaway.value);
formData.append("Number", deathCertificateNo.value);
formData.append("Date", dateToISO(dateDeath.value));
formData.append("Location", placeDeathCertificate.value);
formData.append("Reason", reasonDeath.value);
formData.append("ProfileId", profileId.value);
dialogConfirm($q, () => {
showLoader();
http
.post(config.API.listDeceased(), formData)
.then(() => {
success($q, "บันทึกข้อมูลสำเร็จ");
router.push("/deceased");
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
});
}
function openDialogImg() {
dialogImage.value = true;
getImage();
}
function getImage() {
showLoader();
http
.get(config.API.orgProfileAvatar + `/${profileId.value}`)
.then(async (res) => {
let data = res.data.result;
imagesAlldata.value = data;
for (let i = 0; i < data.length; i++) {
await getImg(data[i]);
}
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
function getImg(dataList: any) {
http
.get(config.API.fileByPath(`${dataList.avatar}/${dataList.avatarName}`))
.then((res) => {
const data = res.data;
const newData = {
id: dataList.id,
isActive: dataList.isActive,
...data,
};
images.value = [...images.value, newData];
console.log(images.value);
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {});
}
function closeImage() {
dialogImage.value = false;
images.value = [];
imagesAlldata.value = [];
}
async function deletePhoto(id: string) {
dialogRemove(
$q,
() => {
showLoader();
http
.delete(config.API.orgProfileAvatar + `/${id}`)
.then((res) => {
images.value = [];
imagesAlldata.value = [];
getImage();
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
},
"ต้องการทำการลบข้อมูลนี้ใช่หรือไม่"
);
}
function imageClass(n: any) {
const val = n == activeImage.value;
return {
"rounded-borders bg-grey-2 image-size-default": val,
"rounded-borders bg-grey-2 image-size-full": !val,
};
}
function getClass(n: any) {
const val = n == activeImage.value;
return {
"rounded-borders border-green shadow-1": val,
"rounded-borders shadow-1": !val,
};
}
async function selectAvatarHistory() {
console.log(activeImage.value);
if (activeImage.value == null) {
dialogMessageNotify($q, "กรุณาเลือกรูปที่ต้องการเปลี่ยน");
return;
}
const data = activeImage.value;
showLoader();
await http
.get(config.API.orgProfileAvatar + `/select/${profileId.value}/${data.id}`)
.then(async (res) => {
closeImage();
await fetchDataPersonal();
await fetchProfile(profileId.value);
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
onMounted(async () => {
// fileName.value = `profile-${profileId.value}`;
await fetchDataPersonal();
// await fetchProfile(profileId.value);
});
</script>
<template>
<div class="row items-center q-gutter-sm q-mb-xs">
<div class="toptitle text-dark row items-center q-py-xs">
<q-btn
icon="mdi-arrow-left"
unelevated
round
dense
flat
color="primary"
class="q-mr-sm"
@click="router.go(-1)"
/>
ทะเบยนประว
</div>
<q-space />
<q-btn-dropdown
size="md"
rounded
unelevated
color="grey-4"
text-color="red"
icon="mdi-home-export-outline"
dropdown-icon="mdi-chevron-down"
>
<q-list
v-if="empType === ''"
v-for="(item, index) in itemsMenu"
:key="index"
>
<q-item
clickable
@click="
item.name == 'ช่วยราชการ'
? helpPost()
: item.name == 'ส่งตัวกลับ'
? repatriationPost()
: item.name == 'แต่งตั้ง-เลื่อน-ย้าย'
? appointPost()
: item.name == 'ถึงแก่กรรม'
? clickPassaway()
: item.name == 'ให้ออกจากราชการ'
? outPost()
: item.name == 'อื่นๆ'
? otherPost()
: null
"
v-close-popup
>
<q-item-section>{{ item.name }}</q-item-section>
</q-item>
</q-list>
<q-list v-else v-for="(item, index) in itemsMenuEmployee" :key="item.id">
<q-item
clickable
@click="
item.name == 'ปรับระดับชั้นงาน - ย้าย'
? appointEmployeePost()
: item.name == 'ถึงแก่กรรม'
? clickPassaway()
: null
"
v-close-popup
>
<q-item-section>{{ item.name }}</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
<q-btn
unelevated
round
color="grey-4"
text-color="primary"
icon="mdi-file-eye-outline"
size="md"
>
<q-tooltip>ดาวนไฟล</q-tooltip>
<q-menu>
<q-list style="min-width: 130px">
<q-item clickable v-close-popup @click="onClickDownloadKp7('FULL')">
<q-item-section class="text-blue">..7/..1</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="onClickDownloadKp7('SHORT')">
<q-item-section class="text-primary">ประวแบบย</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</div>
<q-card>
<div class="column" style="height: 120px">
<div class="col row items-center">
<div class="row col-12">
<div class="col" style="padding-left: 14%">
<div class="col-12 text-primary">
<h2
class="title q-ma-none q-pa-none"
v-if="formDetail && formDetail.firstName && formDetail.lastName"
>
{{
`${formDetail?.prefix}${formDetail?.firstName} ${formDetail?.lastName} ${leaveReason}`
}}
</h2>
</div>
<!-- <div class="col-12 subtitle">{{ formDetail?.position }}</div> -->
</div>
</div>
</div>
<div class="absolute-center-left q-ml-lg">
<q-avatar size="90px" class="bg-grey-2">
<q-img :src="profilePicture" />
</q-avatar>
<q-btn
round
text-color="primary"
icon="mdi-pencil-outline"
@click="openDialogImg"
size="sm"
unelevated
class="bg-white btnEditImg"
>
</q-btn>
</div>
<div class="col row items-center bg-toolbar">
<div class="row col-12" style="padding-left: 14%">
<div class="col-2">
<div class="col-sm-3 col-md-3">
<div class="col text-grey-6 text-caption">
{{ empType === "" ? "ตำแหน่งในสายงาน" : "ตำแหน่ง" }}
</div>
<div class="col">{{ formDetail?.position || "-" }}</div>
</div>
</div>
<div class="col-2">
<div class="col-sm-3 col-md-3">
<div class="col text-grey-6 text-caption">
{{ empType === "" ? "ประเภทตำแหน่ง" : "กลุ่มงาน" }}
</div>
<div class="col">
{{ formDetail?.posType?.posTypeName || "-" }}
</div>
</div>
</div>
<div class="col-2">
<div class="col-sm-3 col-md-3">
<div class="col text-grey-6 text-caption">
{{ empType === "" ? "ระดับตำแหน่ง" : "ระดับชั้นงาน" }}
</div>
<div class="col">
{{ formDetail?.posLevel?.posLevelName || "-" }}
</div>
</div>
</div>
</div>
</div>
</div>
</q-card>
<q-card bordered class="q-mt-md rounded">
<TabMain :fetchDataPersonal="fetchDataPersonal" />
</q-card>
<!-- Dialog แนบใบมรณบตร -->
<q-dialog v-model="dialogPassaway" persistent>
<q-card style="min-width: 600px">
<q-form ref="myForm">
<q-card-section class="flex justify-between" style="padding: 0">
<DialogHeader tittle="ถึงแก่กรรม" :close="closePassaway" />
</q-card-section>
<q-separator />
<q-card-section class="q-pa-md row q-col-gutter-sm">
<q-file
class="col-12 col-sm-6 col-md-5"
outlined
dense
v-model="filePassaway"
label="แนบใบมรณบัตร"
hide-bottom-space
lazy-rules
accept=".pdf"
>
<q-separator />
<template v-slot:prepend>
<q-icon name="attach_file" />
</template>
</q-file>
<q-input
class="col-12 col-sm-6 col-md-7"
dense
outlined
v-model="deathCertificateNo"
label="เลขที่ใบมรณบัตร"
/>
<datepicker
class="col-12 col-sm-6 col-md-5"
menu-class-name="modalfix"
v-model="dateDeath"
:locale="'th'"
autoApply
borderless
:enableTimePicker="false"
week-start="0"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
hide-bottom-space
class="full-width datepicker"
:model-value="dateDeath != null ? date2Thai(dateDeath) : null"
:label="`${'วันที่เสียชีวิต'}`"
:rules="[(val) => !!val || `${'กรุณาเลือกวันที่เสียชีวิต'}`]"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
<q-input
class="col-12 col-sm-6 col-md-7"
dense
outlined
v-model="placeDeathCertificate"
label="สถานที่ออกใบมรณบัตร"
/>
<q-input
class="col-12"
dense
outlined
v-model="reasonDeath"
label="เหตุผลการเสียชีวิต"
type="textarea"
/>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn
unelevated
label="บันทึก"
dense
color="public"
class="q-px-md"
@click="clickSaveDeceased"
:disable="
filePassaway === null ||
deathCertificateNo === '' ||
placeDeathCertificate === '' ||
reasonDeath === ''
"
>
<q-tooltip>นท</q-tooltip>
</q-btn>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
<!-- Dialog เลอก Image -->
<q-dialog v-model="dialogImage" persistent>
<q-card style="width: 100vw; max-width: 60vw">
<q-card-section class="q-py-sm row">
<div class="text-h6">เลอกรปภาพ</div>
<q-space />
<q-btn
icon="close"
unelevated
round
dense
@click="closeImage"
style="color: #ff8080; background-color: #ffdede"
>
<q-tooltip>ดหนาน</q-tooltip>
</q-btn>
</q-card-section>
<q-separator />
<q-card-section class="col-12 row">
<div
class="row wrap items-start col-12 q-col-gutter-sm"
style="height: 320px; overflow: auto"
>
<div class="col-3" @click="selectFile">
<div
style="
height: 160px;
max-width: 15vw;
display: flex !important;
justify-content: center;
align-items: center;
"
class="column rounded-borders cursor-pointer bg-active-image text-white"
>
<q-icon name="add" size="60px" color="white" />
<strong>ปโหลดรปภาพ</strong>
</div>
</div>
<div
v-for="n in images"
:key="n"
class="col-3"
@click="imageActive(n)"
>
<div :class="getClass(n)">
<q-img
v-if="n.downloadUrl != null"
:src="n.downloadUrl"
:class="imageClass(n)"
>
<!-- <div
class="absolute-top bg-transparent cursor-pointer text-right"
style="padding: 5px"
>
<q-btn
icon="delete"
unelevated
round
dense
@click="deletePhoto"
style="color: #ff8080"
/>
</div> -->
<div
class="absolute-bottom col-12 cursor-pointer flex justify-between items-center"
style="padding: 5px"
>
{{ date2Thai(n.createdAt) }}
<q-btn
v-if="!n.isActive"
icon="delete"
unelevated
dense
@click="deletePhoto(n.id)"
class="bg-white"
style="color: #ff8080"
>
<q-tooltip>ลบรปภาพ</q-tooltip>
</q-btn>
</div>
</q-img>
</div>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<!-- <q-btn
flat
round
color="red"
@click="() => {}"
icon="mdi-delete-outline"
>
<q-tooltip>ลบรปภาพ</q-tooltip>
</q-btn> -->
<q-btn
icon="check"
dense
flat
round
@click="selectAvatarHistory"
color="positive"
>
<q-tooltip>เลอกรปภาพ</q-tooltip>
</q-btn>
</q-card-actions>
</q-card>
</q-dialog>
</template>
<style scoped>
h2.title {
font-size: 1.2rem;
line-height: 1.6rem;
font-weight: 500;
}
.subtitle {
font-size: 1rem;
color: #34373c;
}
.absolute-center-left {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.rounded {
border-radius: 10px;
}
.bg-toolbar {
background-color: #f2fbfa;
}
.btnEditImg {
position: absolute;
bottom: 0;
right: 0;
border: 1px solid #ededed;
}
.bg-active-image {
background-color: #52c688;
}
.image-size-default {
height: 150px;
max-width: 15vw;
}
.image-size-full {
height: 160px;
max-width: 15vw;
}
.border-green {
border: 5px solid #52c688;
border-radius: 8px;
}
</style>