From 2d6e42170b191d2ac3a65ebeba8f338f49a4d1bb Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Mon, 14 Jul 2025 14:56:21 +0700 Subject: [PATCH] =?UTF-8?q?[Fix=20=E0=B8=81=E0=B8=B2=E0=B8=A3=E0=B8=A5?= =?UTF-8?q?=E0=B8=B2]=20=E0=B9=81=E0=B8=81=E0=B9=89=E0=B9=84=E0=B8=82?= =?UTF-8?q?=E0=B8=81=E0=B8=B2=E0=B8=A3=E0=B8=A2=E0=B8=B4=E0=B8=87=20api=20?= =?UTF-8?q?=E0=B9=84=E0=B8=9B=20get=20=E0=B8=82=E0=B9=89=E0=B8=AD=E0=B8=A1?= =?UTF-8?q?=E0=B8=B9=E0=B8=A5=E0=B8=9B=E0=B8=A3=E0=B8=B0=E0=B9=80=E0=B8=A0?= =?UTF-8?q?=E0=B8=97=E0=B8=81=E0=B8=B2=E0=B8=A3=E0=B8=A5=E0=B8=B2=E0=B9=81?= =?UTF-8?q?=E0=B8=A5=E0=B8=B0=20position=20=E0=B9=83=E0=B8=99=E0=B8=AB?= =?UTF-8?q?=E0=B8=99=E0=B9=89=E0=B8=B2=E0=B8=A3=E0=B8=B2=E0=B8=A2=E0=B8=A5?= =?UTF-8?q?=E0=B8=B0=E0=B9=80=E0=B8=AD=E0=B8=B5=E0=B8=A2=E0=B8=94=E0=B8=81?= =?UTF-8?q?=E0=B8=B2=E0=B8=A3=E0=B8=81=E0=B8=B2=E0=B8=A3=E0=B8=A5=E0=B8=B2?= =?UTF-8?q?=20=E0=B9=81=E0=B8=A5=E0=B8=B0=E0=B8=A2=E0=B8=81=E0=B9=80?= =?UTF-8?q?=E0=B8=A5=E0=B8=B4=E0=B8=81=E0=B8=81=E0=B8=B2=E0=B8=A3=E0=B8=A5?= =?UTF-8?q?=E0=B8=B2=E0=B9=83=E0=B8=AB=E0=B9=89=E0=B9=80=E0=B8=81=E0=B9=87?= =?UTF-8?q?=E0=B8=9A=E0=B9=83=E0=B8=99=20store?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/interface/response/main.ts | 61 +++++++ .../components/05_Leave/DetailLeavePage.vue | 161 +++++++++--------- .../components/05_Leave/DetailLeaveReject.vue | 129 +++++++------- .../09_leave/interface/request/leave.ts | 4 +- src/modules/09_leave/stores/LeaveStore.ts | 97 +++++++---- 5 files changed, 264 insertions(+), 188 deletions(-) diff --git a/src/interface/response/main.ts b/src/interface/response/main.ts index 2267c36b3..3a9c29851 100644 --- a/src/interface/response/main.ts +++ b/src/interface/response/main.ts @@ -50,6 +50,66 @@ interface DataRoleWorkflow { isStaff: boolean; } +interface DataProfilePosition { + amountSpecial: number; + avatar: string; + avatarName: string; + birthDate: string; + child1: string; + child1DnaId: string; + child1Id: string; + child1ShortName: string; + child2: string; + child2DnaId: string; + child2Id: string; + child2ShortName: string; + child3: string; + child3DnaId: string; + child3Id: string; + child3ShortName: string; + child4: string; + child4DnaId: string; + child4Id: null; + child4ShortName: string; + citizenId: string; + dateRetireLaw: string; + dateStart: string; + firstName: string; + isDirector: boolean; + isProbation: boolean; + keycloak: string; + lastName: string; + leaveDate: string; + node: number; + nodeDnaId: string; + nodeId: string; + nodeShortName: string; + posExecutiveId: string; + posExecutiveName: string; + posExecutivePriority: string; + posLevelId: string; + posLevelName: string; + posLevelRank: number; + posMaster: number; + posMasterNo: number; + posNo: string; + posTypeId: string; + posTypeName: string; + posTypeRank: number; + position: string; + positionArea: string; + positionExecutiveField: string; + prefix: string; + profileId: string; + profileType: string; + rank: string; + root: string; + rootDnaId: string; + rootId: string; + rootShortName: string; + salary: number; +} + export type { ListMenu, ChildLevelTree, @@ -57,4 +117,5 @@ export type { DataPermissions, DataRoles, DataRoleWorkflow, + DataProfilePosition, }; diff --git a/src/modules/09_leave/components/05_Leave/DetailLeavePage.vue b/src/modules/09_leave/components/05_Leave/DetailLeavePage.vue index df67dc137..0387976c0 100644 --- a/src/modules/09_leave/components/05_Leave/DetailLeavePage.vue +++ b/src/modules/09_leave/components/05_Leave/DetailLeavePage.vue @@ -12,7 +12,8 @@ import { checkPermission } from "@/utils/permissions"; import { useRoleWorkflowDataStore } from "@/stores/roleWorkflow"; /** importType */ -import type { FremData } from "@/modules/09_leave/interface/request/leave"; +import type { DataProfilePosition } from "@/interface/response/main"; +import type { FormData } from "@/modules/09_leave/interface/request/leave"; import type { LeaveType, SeqTypeRow, @@ -33,7 +34,6 @@ import FormLeaveToTraining from "@/modules/09_leave/components/05_Leave/formDeta import FormLeaveToWorkInternational from "@/modules/09_leave/components/05_Leave/formDetail/formLeaveToWorkInternational.vue"; // ลาไปปฏิบัติงานในองค์การระหว่างประเทศ import FormSpouse from "@/modules/09_leave/components/05_Leave/formDetail/formSpouse.vue"; // ลาติดตามคู่สมรส import FormVocationalRehabilitation from "@/modules/09_leave/components/05_Leave/formDetail/formVocationalRehabilitation.vue"; //ลาไปฟื้นฟูสมรรถภาพด้านอาชีพ -import WorkFlow from "@/components/Workflow/Main.vue"; import DialogAddCommander from "@/modules/09_leave/components/05_Leave/Dialog/DialogAddCommander.vue"; /** use */ @@ -51,20 +51,20 @@ const { const stores = useLeavelistDataStore(); const router = useRouter(); const route = useRoute(); -const paramsId = route.params.id.toString(); -const keycloakId = ref(""); -const keycloakUserId = ref(""); -const workflowRef = ref(null); -const modalApprove = ref(false); -const statusCheck = ref(""); -const typeDocx = ref("docx"); -const typePdf = ref("pdf"); -const dialogTitle = ref("อนุญาต"); -const dialogLabel = ref("เหตุผล"); -const modalAdd = ref(false); -const typeAdd = ref(""); + +const paramsId = route.params.id.toString(); // ID การยื่นขอลา +const keycloakId = ref(""); // Keycloak ID +const keycloakUserId = ref(""); // Keycloak User ID +const modalApprove = ref(false); // เปิด Modal อนุมัติการลา +const statusCheck = ref(""); // สถานะการลา +const typeDocx = ref("docx"); // ประเภทไฟล์ที่ต้องการดาวน์โหลด +const typePdf = ref("pdf"); // ประเภทไฟล์ที่ต้องการดาวน์โหลด +const dialogTitle = ref("อนุญาต"); // Title ของ Dialog +const dialogLabel = ref("เหตุผล"); // Label ของ Dialog +const modalAdd = ref(false); // เปิด Modal เพิ่มผู้บังคับบัญชา +const typeAdd = ref(""); // ประเภทการเพิ่ม เช่น COMMANDER, APPROVER /** Form รายละเอียดข้อมูล*/ -const formData = reactive({ +const formData = reactive({ id: "", //Id การยื่นขอลา reasonCommander: "", //เหตุผลผู้บังคับบัญชา reasonOligarch: "", //เหตุผลผู้มีอำนาจ @@ -138,10 +138,14 @@ const formData = reactive({ leaveRangeEnd: "", }); -const isOfficer = ref(false); -const isStaff = ref(false); -const isLoadData = ref(false); +const checkForm = ref(""); // ประเภทของฟอร์มที่จะแสดง +const leaveType = ref([]); // ประเภทการลา +const isOfficer = ref(false); // เช็คว่าเป็นสกจ. +const isStaff = ref(false); // เช็คว่าเป็นการเจ้าหน้าที่ +const isLoadData = ref(false); // เช็คว่าข้อมูลโหลดเสร็จหรือไม่ const rows = ref(); + +// เช็คสิทธิ์การอนุมัติ const idCheck = computed(() => { if (typeAdd.value == "COMMANDER") { return rows.value?.commanders.map((items: SeqTypeRow) => items.profileId); @@ -150,6 +154,7 @@ const idCheck = computed(() => { } }); +// เช็คว่าผู้ใช้มีสิทธิ์อนุมัติหรือไม่ const approveCheck = computed(() => { return ( rows.value?.commanders?.every( @@ -158,6 +163,7 @@ const approveCheck = computed(() => { ); }); +// เช็คว่าผู้ใช้มีสิทธิ์อนุมัติที่รอดำเนินการหรือไม่ const approvePendingCheck = computed(() => { const commanders = rows.value?.commanders || []; const index = commanders.findIndex((c) => c.profileId === keycloakId.value); @@ -224,12 +230,11 @@ const columns = ref([ }, ]); /** - * Function fetch รายละเอียดของข้อมูล + * ฟังก์ชั่นเรียกรายละเอียดของข้อมูล * @param paramsId รับ ID จาก paramID */ async function fetchDetailLeave(paramsId: string) { isLoadData.value = false; - showLoader(); await http .get(config.API.leaveListById(paramsId)) .then(async (res) => { @@ -379,37 +384,26 @@ async function fetchDetailLeave(paramsId: string) { }; isLoadData.value = true; - // await fetchOptionType(); }) .catch((err) => { messageError($q, err); - }) - .finally(() => { - hideLoader(); }); } -const leaveType = ref(); +/** ฟังก์ชันดึงประเภทการลา */ async function fetchOptionType() { - await http - .get(config.API.leaveType()) - .then((res) => { - leaveType.value = res.data.result; - }) - .catch((err) => { - messageError($q, err); - }); + leaveType.value = await stores.leaveTypeList(); } -/**Status Form การลา*/ -const checkForm = ref(""); + /** - * Function เช็คประเภทการลา - * @param type รับค่า + * ฟังก์ชันเช็คประเภทการลา + * @param type รับค่า ประเภทการลา + * @param formData รับค่า FormData */ -function checkLeaveType(leaveTypeId: string, formData: FremData) { +async function checkLeaveType(leaveTypeId: string, formData: FormData) { if (leaveType.value) { const filtertype: LeaveType | undefined = leaveType.value.find( - (e: any) => e.id === leaveTypeId + (e: LeaveType) => e.id === leaveTypeId ); const type = filtertype?.code; if (type === "LV-001" || type === "LV-002" || type === "LV-003") { @@ -445,7 +439,10 @@ function checkLeaveType(leaveTypeId: string, formData: FremData) { } } -/** Function dialog*/ +/** + * ฟังก์ชันเปิด Modal + * @param data ประเภทของ Modal + */ async function openModal(data: string) { if (data === "approve") { modalApprove.value = true; @@ -462,17 +459,10 @@ async function openModal(data: string) { } } -// /** function ส่งไปผู้บังคับบัญชา*/ -// function sendToCommand() { -// dialogConfirm( -// $q, -// async () => {}, -// "ยืนยันการส่งไปผู้บังคับบัญชา", -// "ต้องการยืนยันการส่งไปผู้บังคับบัญชานี้ใช่หรือไม่?" -// ); -// } - -/** Function Save */ +/** + * ฟังก์ชันบันทึกข้อมูลการอนุมัติ + * @param reason เหตุผลในการอนุมัติ + */ function clickSave(reason: string) { const body = { reason: reason, @@ -493,7 +483,7 @@ function clickSave(reason: string) { .catch((err) => { messageError($q, err); }) - .finally(async () => { + .finally(() => { hideLoader(); }); }, @@ -560,6 +550,12 @@ function clickSave(reason: string) { } } +/** + * ฟังก์ชันดาวน์โหลดไฟล์ + * @param id รหัสการลา + * @param fileName ชื่อไฟล์ + * @param type ประเภทไฟล์ + */ async function onClickDownloadFile(id: string, fileName: string, type: string) { showLoader(); await http @@ -576,42 +572,49 @@ async function onClickDownloadFile(id: string, fileName: string, type: string) { }); } +/** + * ฟังก์ชันจัดรูปแบบหมายเลข + * @param x หมายเลขที่ต้องการจัดรูปแบบ + * @returns หมายเลขที่จัดรูปแบบแล้ว + */ function formattedNumber(x: number) { return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } -const isCheckData = computed(() => { - if (formData.reasonCommander !== "-" && formData.reasonOligarch !== "-") { - return true; - } else return false; -}); - +/** + * ฟังก์ชันเปิด Modal เพื่อเพิ่มผู้บังคับบัญชา + * @param type ประเภทการเพิ่ม เช่น ผู้บังคับบัญชา, ผู้มีอำนาจ + */ function onAddPerson(type: string) { modalAdd.value = true; typeAdd.value = type; } +/** ฟังก์ชันส่งข้อมูลไปพิจารณา */ function onSend() { dialogConfirm( $q, - () => { + async () => { showLoader(); - http + await http .get(config.API.sendApprove(paramsId)) - .then(async (res) => { + .then(async () => { await fetchDetailLeave(paramsId); success($q, "ส่งไปพิจารณา"); }) .catch((e) => { messageError($q, e); }) - .finally(() => {}); + .finally(() => { + hideLoader(); + }); }, "ยืนยันการส่งไปพิจารณา", "ต้องการส่งไปพิจารณาใช่หรือไม่" ); } +/** ฟังก์ชันตรวจสอบสถานะเจ้าหน้าที่ */ async function checkOfficer() { try { const data = await fetchDataCheckIsoffice( @@ -628,30 +631,30 @@ async function checkOfficer() { } } -async function fetchKeycloakPosition() { +/** ฟังก์ชันดึงข้อมูลตำแหน่งจาก Keycloak */ +async function fetchKeycloakPositionData() { if (keycloakId.value == "") { - await http - .get(config.API.keycloakPosition()) - .then(async (res) => { - const data = await res.data.result; - keycloakId.value = data.profileId; - }) - .catch((err) => { - messageError($q, err); - }); + const data: DataProfilePosition = await stores.fetchKeycloakPosition(); + keycloakId.value = data?.profileId ?? ""; } } +/** lifecycle hook */ onMounted(async () => { if (paramsId) { - await Promise.all([ - fetchOptionType(), - fetchKeycloakPosition(), - fetchDetailLeave(paramsId), - checkOfficer(), - ]); + try { + showLoader(); + await Promise.all([ + fetchOptionType(), + fetchKeycloakPositionData(), + fetchDetailLeave(paramsId), + checkOfficer(), + ]); - checkLeaveType(formData.leaveTypeId, formData); + await checkLeaveType(formData.leaveTypeId, formData); + } finally { + hideLoader(); + } } }); diff --git a/src/modules/09_leave/components/05_Leave/DetailLeaveReject.vue b/src/modules/09_leave/components/05_Leave/DetailLeaveReject.vue index c08ff9d3e..5bc690811 100644 --- a/src/modules/09_leave/components/05_Leave/DetailLeaveReject.vue +++ b/src/modules/09_leave/components/05_Leave/DetailLeaveReject.vue @@ -8,16 +8,16 @@ import config from "@/app.config"; import genReport from "@/plugins/genreport"; import { useCounterMixin } from "@/stores/mixin"; import { useLeavelistDataStore } from "@/modules/09_leave/stores/LeaveStore"; -import { checkPermission } from "@/utils/permissions"; import { useRoleWorkflowDataStore } from "@/stores/roleWorkflow"; /** importType */ +import type { DataProfilePosition } from "@/interface/response/main"; import type { LeaveType, FormReject, RowsType, } from "@/modules/09_leave/interface/response/leave"; -import type { FremData } from "@/modules/09_leave/interface/request/leave"; +import type { FormData } from "@/modules/09_leave/interface/request/leave"; /** importForm*/ import DialogReason from "@/components/Dialogs/PopupReason.vue"; @@ -56,21 +56,6 @@ const typeDocx = ref("docx"); const typePdf = ref("pdf"); const modalApprove = ref(false); const dialogTitle = ref("อนุญาต"); -// const approveCheck = computed(() => { -// return ( -// rows.value?.commanders?.every( -// (commander) => commander.approveStatus === "APPROVE" -// ) ?? false -// ); -// }); - -/** ฟังก์ชั่น อัปโหลด - * consolelog ไว้ก่อน - */ -const filesUpload = ref(null); -function upLoadFile() { - console.log("upload", filesUpload.value); -} const rows = ref(); const statusCheck = ref(""); @@ -95,7 +80,7 @@ const formDataReject = reactive({ leaveDirectorComment: "", //ความคิดเห็นของผู้บังคับบัญชา }); -const formData = reactive({ +const formData = reactive({ id: "", //Id การยื่นขอลา reasonCommander: "", //เหตุผลผู้บังคับบัญชา reasonOligarch: "", //เหตุผลผู้มีอำนาจ @@ -169,25 +154,11 @@ const formData = reactive({ }); const isLoadData = ref(false); - -onMounted(async () => { - if (paramsId) { - showLoader(); - Promise.all([ - fetchOptionType(), - fetchDetailDeleteLeave(paramsId), - fetchKeycloakPosition(), - fetchDetailLeave(paramsId), - checkOfficer(), - ]).finally(() => { - checkLeaveType(formData.leaveTypeId, formData.leaveSubTypeName); - hideLoader(); - }); - } -}); +const leaveType = ref([]); //ประเภทการลา +const checkForm = ref(""); //เช็คประเภทการลา /** - * Function fetch รายละเอียดของข้อมูล + * ฟังก์เรียกข้อมูลรายละเอียดของการยกเลิกลา * @param paramsId รับ ID จาก paramID */ async function fetchDetailDeleteLeave(paramsId: string) { @@ -217,6 +188,10 @@ async function fetchDetailDeleteLeave(paramsId: string) { }); } +/** + * ฟังก์เรียกข้อมูลรายละเอียดของการลา + * @param paramsId รับ ID จาก paramID + */ async function fetchDetailLeave(paramsId: string) { isLoadData.value = false; await http @@ -313,36 +288,25 @@ async function fetchDetailLeave(paramsId: string) { commanders: data.commanders, approvers: data.approvers, }; - // await fetchOptionType(); }) .catch((err) => { messageError($q, err); }); } -const leaveType = ref(); -/** function เรียกประเภทการลา */ +/** ฟังก์ชันเรียกประเภทการลา */ async function fetchOptionType() { - await http - .get(config.API.leaveType()) - .then((res) => { - leaveType.value = res.data.result; - }) - .catch((err) => { - messageError($q, err); - }); + leaveType.value = await stores.leaveTypeList(); } -/**Status Form การลา*/ -const checkForm = ref(""); /** - * Function เช็คประเภทการลา - * @param type รับค่า + * ฟังก์ชันเช็คประเภทการลา + * @param type รับค่า ID ประเภทการลา */ -function checkLeaveType(leaveTypeId: string, leaveTypeName: string) { +async function checkLeaveType(leaveTypeId: string, leaveTypeName: string) { if (leaveType.value) { const filtertype: LeaveType | undefined = leaveType.value.find( - (e: any) => e.id === leaveTypeId + (e: LeaveType) => e.id === leaveTypeId ); const type = filtertype?.code; if (type === "LV-001" || type === "LV-002" || type === "LV-003") { @@ -378,8 +342,11 @@ function checkLeaveType(leaveTypeId: string, leaveTypeName: string) { } } -/** Function dialog*/ -const openModal = async (data: string) => { +/** + * ฟังก์ชันเปิด modal อนุมัติการยกเลิกลา + * @param data ข้อมูลที่ใช้ในการเปิด modal เช่น "approve" หรือ "UnApprove" + */ +function openModal(data: string) { if (data === "approve") { modalApprove.value = true; dialogTitle.value = "อนุญาตให้ยกเลิกการลา"; @@ -388,9 +355,12 @@ const openModal = async (data: string) => { modalApprove.value = true; dialogTitle.value = "ไม่อนุญาตให้ยกเลิกการลา"; } -}; +} -/** Function Save*/ +/** + * ฟังก์ชันบันทึกข้อมูลการอนุมัติ + * @param reason เหตุผลในการอนุมัติ + */ function clickSave(reason: string) { const body = { reason: reason, @@ -402,15 +372,15 @@ function clickSave(reason: string) { showLoader(); await http .put(config.API.leaveDeleteApprove(formDataReject.id), body) - .then(() => { + .then(async () => { + await fetchDetailDeleteLeave(paramsId); + modalApprove.value = false; success($q, "บันทึกข้อมูลสำเร็จ"); }) .catch((err) => { messageError($q, err); }) .finally(async () => { - await fetchDetailDeleteLeave(paramsId); - modalApprove.value = false; hideLoader(); }); }, @@ -425,15 +395,15 @@ function clickSave(reason: string) { showLoader(); await http .put(config.API.leaveDeleteReject(formDataReject.id), body) - .then(() => { + .then(async () => { + await fetchDetailDeleteLeave(paramsId); + modalApprove.value = false; success($q, "บันทึกข้อมูลสำเร็จ"); }) .catch((err) => { messageError($q, err); }) .finally(async () => { - await fetchDetailDeleteLeave(paramsId); - modalApprove.value = false; hideLoader(); }); }, @@ -443,6 +413,12 @@ function clickSave(reason: string) { } } +/** + * ฟังก์ชันดาวน์โหลดไฟล์เอกสารการลา + * @param id ID ของการลา + * @param fileName ชื่อไฟล์ที่ต้องการดาวน์โหลด + * @param type ประเภทไฟล์ เช่น "docx" หรือ "pdf" + */ async function onClickDownloadFile(id: string, fileName: string, type: string) { showLoader(); await http @@ -459,6 +435,7 @@ async function onClickDownloadFile(id: string, fileName: string, type: string) { }); } +/** ฟังก์ชันตรวจสอบสถานะเจ้าหน้าที่ */ async function checkOfficer() { try { const data = await fetchDataCheckIsoffice( @@ -475,19 +452,29 @@ async function checkOfficer() { } } +/** ฟังก์ชันดึงข้อมูลตำแหน่งจาก Keycloak */ async function fetchKeycloakPosition() { if (myProfileId.value == "") { - await http - .get(config.API.keycloakPosition()) - .then(async (res) => { - const data = await res.data.result; - myProfileId.value = data.profileId; - }) - .catch((err) => { - messageError($q, err); - }); + const data: DataProfilePosition = await stores.fetchKeycloakPosition(); + myProfileId.value = data?.profileId ?? ""; } } + +onMounted(async () => { + if (paramsId) showLoader(); + try { + await Promise.all([ + fetchOptionType(), + fetchDetailDeleteLeave(paramsId), + fetchKeycloakPosition(), + fetchDetailLeave(paramsId), + checkOfficer(), + ]); + await checkLeaveType(formData.leaveTypeId, formData.leaveSubTypeName); + } finally { + hideLoader(); + } +});