From 06ddc1c970450249212e37edee49492a7e45e90e Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Tue, 16 Jun 2026 10:43:31 +0700 Subject: [PATCH 01/38] refactor(org): add ROOT_CODE and CHILD_CODE fields for org hierarchy --- .../components/DialogFormAgency.vue | 107 ++++++++++++++++-- .../components/DialogStructureDetail.vue | 45 ++++++++ .../02_organization/interface/index/Main.ts | 5 + 3 files changed, 145 insertions(+), 12 deletions(-) diff --git a/src/modules/02_organization/components/DialogFormAgency.vue b/src/modules/02_organization/components/DialogFormAgency.vue index 32873fc17..72b3d228c 100644 --- a/src/modules/02_organization/components/DialogFormAgency.vue +++ b/src/modules/02_organization/components/DialogFormAgency.vue @@ -89,6 +89,11 @@ const formData = reactive({ DIVISION_CODE: "", SECTION_CODE: "", JOB_CODE: "", + ROOT_CODE: "", + CHILD1_CODE: "", + CHILD2_CODE: "", + CHILD3_CODE: "", + CHILD4_CODE: "", }); /** @@ -160,6 +165,11 @@ function onSubmit() { DIVISION_CODE: formData.DIVISION_CODE, SECTION_CODE: formData.SECTION_CODE, JOB_CODE: formData.JOB_CODE, + ROOT_CODE: formData.ROOT_CODE, + CHILD1_CODE: formData.CHILD1_CODE, + CHILD2_CODE: formData.CHILD2_CODE, + CHILD3_CODE: formData.CHILD3_CODE, + CHILD4_CODE: formData.CHILD4_CODE, }; // เพิ่มข้อมูล @@ -189,18 +199,20 @@ function onSubmit() { body ) .then(async () => { - await props.fetchDataTree(store.draftId); - await props.edit?.( - props.dataNode?.orgTreeId, - type, - body, - props.dataNode?.orgRootCode - ); - await props.fetchDataTable( - props?.dataNode?.orgTreeId, - props?.dataNode?.orgLevel, - false - ); + await Promise.all([ + await props.fetchDataTree(store.draftId), + await props.edit?.( + props.dataNode?.orgTreeId, + type, + body, + props.dataNode?.orgRootCode + ), + await props.fetchDataTable( + props?.dataNode?.orgTreeId, + props?.dataNode?.orgLevel, + false + ), + ]); await success($q, "บันทึกข้อมูลสำเร็จ"); closeClear(); }) @@ -231,6 +243,11 @@ function closeClear() { formData.isCommission = false; formData.isInformation = false; formData.misId = ""; + formData.ROOT_CODE = ""; + formData.CHILD1_CODE = ""; + formData.CHILD2_CODE = ""; + formData.CHILD3_CODE = ""; + formData.CHILD4_CODE = ""; formData.DEPARTMENT_CODE = ""; formData.DIVISION_CODE = ""; formData.SECTION_CODE = ""; @@ -456,6 +473,7 @@ watch( else { props.dataNode?.orgLevel === 1 && checkOfficer(); if (props.dataNode) { + console.log(props.dataNode); formData.orgName = props.dataNode.orgTreeName; formData.orgShortName = props.dataNode.orgTreeShortName; formData.orgCode = props.dataNode.orgTreeCode; @@ -474,6 +492,11 @@ watch( formData.DIVISION_CODE = props.dataNode.DIVISION_CODE; formData.SECTION_CODE = props.dataNode.SECTION_CODE; formData.JOB_CODE = props.dataNode.JOB_CODE; + formData.ROOT_CODE = props.dataNode.ROOT_CODE; + formData.CHILD1_CODE = props.dataNode.CHILD1_CODE; + formData.CHILD2_CODE = props.dataNode.CHILD2_CODE; + formData.CHILD3_CODE = props.dataNode.CHILD3_CODE; + formData.CHILD4_CODE = props.dataNode.CHILD4_CODE; orgLevelOption.value = props.dataNode.orgTreeRank === "DEPARTMENT" ? orgLevelOptionMain.value @@ -730,6 +753,66 @@ watch( +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
{ messageError($q, err); @@ -208,6 +218,41 @@ watch(
+
+
ROOT CODE
+
+

{{ formData.rootCode }}

+
+
+ +
+
CHILD1 CODE
+
+

{{ formData.child1Code }}

+
+
+ +
+
CHILD2 CODE
+
+

{{ formData.child2Code }}

+
+
+ +
+
CHILD3 CODE
+
+

{{ formData.child3Code }}

+
+
+ +
+
CHILD4 CODE
+
+

{{ formData.child4Code }}

+
+
+
หน้าที่ความรับผิดชอบ
diff --git a/src/modules/02_organization/interface/index/Main.ts b/src/modules/02_organization/interface/index/Main.ts index 8550b47e9..0103568c2 100644 --- a/src/modules/02_organization/interface/index/Main.ts +++ b/src/modules/02_organization/interface/index/Main.ts @@ -44,6 +44,11 @@ interface FormDataAgency { DIVISION_CODE: string; SECTION_CODE: string; JOB_CODE: string; + ROOT_CODE: string; + CHILD1_CODE: string; + CHILD2_CODE: string; + CHILD3_CODE: string; + CHILD4_CODE: string; } interface FormDataPosition { From df9a8408dd64fec048c9e04b4ba7a702b35614e9 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Tue, 16 Jun 2026 16:07:24 +0700 Subject: [PATCH 02/38] refactor(leave): add isAllDirector field to workflowCommanderOperate API --- .../05_Leave/Dialog/DialogAddCommander.vue | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/modules/09_leave/components/05_Leave/Dialog/DialogAddCommander.vue b/src/modules/09_leave/components/05_Leave/Dialog/DialogAddCommander.vue index e7697ce5b..fa61ca17f 100644 --- a/src/modules/09_leave/components/05_Leave/Dialog/DialogAddCommander.vue +++ b/src/modules/09_leave/components/05_Leave/Dialog/DialogAddCommander.vue @@ -35,6 +35,7 @@ const props = defineProps({ const pageId = ref(route.params.id as string); const keyword = ref(""); const isAct = ref(false); +const isAllDirector = ref(false); const total = ref(0); const totalList = ref(1); @@ -105,6 +106,7 @@ async function getData() { page: pagination.value.page, keyword: keyword.value, isAct: isAct.value, + isAllDirector: isAllDirector.value, keycloakId: props.keycloakUserId, type: props.profileType?.toLocaleLowerCase() === "officer" @@ -196,6 +198,7 @@ function closeDialog() { modal.value = false; rows.value = []; selected.value = []; + isAllDirector.value = false; } watch( @@ -231,19 +234,45 @@ watch(
-
+
+ + + + +
+ +
+ + หัวหน้าทั้งหน่วยงาน + - แสดงเฉพาะรักษาการแทน + แสดงเฉพาะรักษาการแทน - - -
+
{{ props.type == "APPROVER" From 004a0bcdb3c45f6c88abf4dc85941d9f17e81664 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Wed, 17 Jun 2026 15:26:47 +0700 Subject: [PATCH 03/38] refactor(registry): rules q-select rank --- .../detail/PersonalInformation/02_NameChangeHistory.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue b/src/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue index 05ee33629..0daa26c1f 100644 --- a/src/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue +++ b/src/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue @@ -661,7 +661,7 @@ onMounted(async () => { lazy-rules emit-value map-options - :rules="[(val:string) => !!val || `${'กรุณาเลือกยศ'}`]" + :rules="selection.includes('rank') ? [(val:string) => !!val || `${'กรุณาเลือกยศ'}`] : []" hide-bottom-space input-debounce="0" option-label="name" From 695c9ee271f1c5f9fd58f8b9ff0e67b232d2910d Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Wed, 17 Jun 2026 15:27:20 +0700 Subject: [PATCH 04/38] fix --- .../detail/PersonalInformation/02_NameChangeHistory.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue b/src/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue index 0daa26c1f..73bab2a70 100644 --- a/src/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue +++ b/src/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue @@ -661,7 +661,6 @@ onMounted(async () => { lazy-rules emit-value map-options - :rules="selection.includes('rank') ? [(val:string) => !!val || `${'กรุณาเลือกยศ'}`] : []" hide-bottom-space input-debounce="0" option-label="name" From 82411ce499269be556a0f74bb071ee6ffb6d9486 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Wed, 17 Jun 2026 16:50:59 +0700 Subject: [PATCH 05/38] fix --- .../components/detail/PersonalInformation/01_Profile.vue | 2 +- .../detail/PersonalInformation/02_NameChangeHistory.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/04_registryPerson/components/detail/PersonalInformation/01_Profile.vue b/src/modules/04_registryPerson/components/detail/PersonalInformation/01_Profile.vue index d37b57f06..9df95660d 100644 --- a/src/modules/04_registryPerson/components/detail/PersonalInformation/01_Profile.vue +++ b/src/modules/04_registryPerson/components/detail/PersonalInformation/01_Profile.vue @@ -304,7 +304,7 @@ function onClickOpenDialog() { id.value = informaData.value.id; age.value = calculateAge(informaData.value.birthDate); formData.citizenId = informaData.value.citizenId; - formData.prefix = informaData.value.prefix; + formData.prefix = informaData.value.prefixMain; formData.rank = informaData.value.rank; formData.firstName = informaData.value.firstName; formData.lastName = informaData.value.lastName; diff --git a/src/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue b/src/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue index 73bab2a70..06b598ad8 100644 --- a/src/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue +++ b/src/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue @@ -475,7 +475,7 @@ onMounted(async () => { icon="add" @click=" () => { - changeNameData.prefix = profileInfo?.prefix; + changeNameData.prefix = profileInfo?.prefixMain; changeNameData.firstName = profileInfo?.firstName; changeNameData.lastName = profileInfo?.lastName; changeNameData.rank = profileInfo?.rank; From c1d30de6d265f15f13168b71c6a270758432bb04 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Wed, 17 Jun 2026 17:30:23 +0700 Subject: [PATCH 06/38] fix --- .../components/detail/PersonalInformation/01_Profile.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/04_registryPerson/components/detail/PersonalInformation/01_Profile.vue b/src/modules/04_registryPerson/components/detail/PersonalInformation/01_Profile.vue index 9df95660d..0b2bca785 100644 --- a/src/modules/04_registryPerson/components/detail/PersonalInformation/01_Profile.vue +++ b/src/modules/04_registryPerson/components/detail/PersonalInformation/01_Profile.vue @@ -96,11 +96,11 @@ const columnsHistory = ref([ a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }), }, { - name: "prefix", + name: "prefixMain", align: "left", label: "คำนำหน้าชื่อ", sortable: true, - field: "prefix", + field: "prefixMain", headerStyle: "font-size: 14px", style: "font-size: 14px", sort: (a: string, b: string) => @@ -256,7 +256,7 @@ const columnsHistory = ref([ ]); const visibleColumnsHistory = ref([ "citizenId", - "prefix", + "prefixMain", "rank", "firstName", "lastName", From ee82e63e251aa94bf2f14ede3fbbaeaf97db5927 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Wed, 17 Jun 2026 18:11:30 +0700 Subject: [PATCH 07/38] refactor(position-temp): comment checkbox isSit --- src/modules/20_positionTemp/components/DialogSelectPerson.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/20_positionTemp/components/DialogSelectPerson.vue b/src/modules/20_positionTemp/components/DialogSelectPerson.vue index 6498094be..0c6ca2dac 100644 --- a/src/modules/20_positionTemp/components/DialogSelectPerson.vue +++ b/src/modules/20_positionTemp/components/DialogSelectPerson.vue @@ -706,7 +706,7 @@ watch(
-
+
From 20d80916cb59143c6458d04f2ad841ec8de32281 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Fri, 19 Jun 2026 15:45:19 +0700 Subject: [PATCH 08/38] refactor(command): validate commandCode === 'C-PM-47' --- src/modules/18_command/components/Step/1_Detail.vue | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/modules/18_command/components/Step/1_Detail.vue b/src/modules/18_command/components/Step/1_Detail.vue index 2a3f3b60f..fdbff84aa 100644 --- a/src/modules/18_command/components/Step/1_Detail.vue +++ b/src/modules/18_command/components/Step/1_Detail.vue @@ -113,8 +113,6 @@ const visibleColumns = ref>([ const modalAddOperator = ref(false); // แสดงเพิ่มรายชื่อลงนามในแนบท้ายคำสั่ง - - /** * ฟังก์ชันบันทึกข้อมูลรายละเอียดคำสั่ง * และกำหนด isChangeData เป็น false @@ -124,7 +122,8 @@ async function onSubmit() { if ( store.isIdofficer && formData.isBangkok !== "BANGKOK" && - formData.isBangkok !== "OFFICE" + formData.isBangkok !== "OFFICE" && + commandCode.value !== "C-PM-47" ) { dialogMessageNotify($q, "กรุณาเลือกคำสั่ง"); return; From 2dfe6172846436db0cbbd065617154f45e73490f Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Mon, 22 Jun 2026 09:28:50 +0700 Subject: [PATCH 09/38] refactor(command): readonly radio commandCode C-PM-47 --- .../18_command/components/Step/1_Detail.vue | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/modules/18_command/components/Step/1_Detail.vue b/src/modules/18_command/components/Step/1_Detail.vue index fdbff84aa..4ab0839a5 100644 --- a/src/modules/18_command/components/Step/1_Detail.vue +++ b/src/modules/18_command/components/Step/1_Detail.vue @@ -122,8 +122,7 @@ async function onSubmit() { if ( store.isIdofficer && formData.isBangkok !== "BANGKOK" && - formData.isBangkok !== "OFFICE" && - commandCode.value !== "C-PM-47" + formData.isBangkok !== "OFFICE" ) { dialogMessageNotify($q, "กรุณาเลือกคำสั่ง"); return; @@ -224,6 +223,8 @@ onMounted(async () => { formData.commandExcecuteDate = props.formCommandList.commandExcecuteDate; formData.isBangkok = !store.isIdofficer ? null + : props.formCommandList.commandCode === "C-PM-47" + ? "OFFICE" : props.formCommandList.isBangkok; commandCode.value = props.formCommandList.commandCode; const [volume, chapter] = props.formCommandList.commandNo.split("/"); @@ -485,12 +486,9 @@ onMounted(async () => { />
-
+
{ /> Date: Mon, 22 Jun 2026 10:45:45 +0700 Subject: [PATCH 10/38] refactor(command): default isBangkok to true when commandCode is 'C-PM-47' --- src/modules/18_command/components/Step/1_Detail.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/18_command/components/Step/1_Detail.vue b/src/modules/18_command/components/Step/1_Detail.vue index 4ab0839a5..0c3755cfb 100644 --- a/src/modules/18_command/components/Step/1_Detail.vue +++ b/src/modules/18_command/components/Step/1_Detail.vue @@ -224,7 +224,7 @@ onMounted(async () => { formData.isBangkok = !store.isIdofficer ? null : props.formCommandList.commandCode === "C-PM-47" - ? "OFFICE" + ? "BANGKOK" : props.formCommandList.isBangkok; commandCode.value = props.formCommandList.commandCode; const [volume, chapter] = props.formCommandList.commandNo.split("/"); From 76156d03e4f2c07433fe6eced18799499e7c1f67 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Mon, 22 Jun 2026 11:03:58 +0700 Subject: [PATCH 11/38] refactor(round-time): replace max-height DialogForm --- .../09_leave/components/01_RoundTime/DialogForm.vue | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/modules/09_leave/components/01_RoundTime/DialogForm.vue b/src/modules/09_leave/components/01_RoundTime/DialogForm.vue index c6883cb11..8eaf9c6b5 100644 --- a/src/modules/09_leave/components/01_RoundTime/DialogForm.vue +++ b/src/modules/09_leave/components/01_RoundTime/DialogForm.vue @@ -212,7 +212,7 @@ watch( :close="close" /> - +
@@ -362,6 +362,7 @@ watch(
+
@@ -513,6 +514,7 @@ watch(
+ + /> +
@@ -541,6 +544,7 @@ watch(
+
@@ -559,6 +563,7 @@ watch(
+
From 63f307c70d2c7bdd5199f1361b8b43aed686517b Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Tue, 23 Jun 2026 13:41:10 +0700 Subject: [PATCH 12/38] feat(timestamp-special): add MultipleApprove Special Lists --- src/api/09_leave/api.leave.ts | 1 + .../04_SpecialTime/DialogMultipleApprove.vue | 325 ++++++++++++++++++ src/modules/09_leave/interface/index/Main.ts | 2 + .../09_leave/views/04_SpecialTimeMain.vue | 26 +- 4 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue diff --git a/src/api/09_leave/api.leave.ts b/src/api/09_leave/api.leave.ts index d0229b204..3ea0ab8c3 100644 --- a/src/api/09_leave/api.leave.ts +++ b/src/api/09_leave/api.leave.ts @@ -25,6 +25,7 @@ export default { specialTime: () => `${leave}/admin/edit`, specialTimeApprove: (id: string) => `${leave}/admin/edit/approve/${id}`, specialTimeReject: (id: string) => `${leave}/admin/edit/reject/${id}`, + specialTimeApproveLists: `${leave}/admin/edit/approve-list`, /** รายการลา*/ leaveType: () => `${leave}/type`, diff --git a/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue b/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue new file mode 100644 index 000000000..54484d7bd --- /dev/null +++ b/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue @@ -0,0 +1,325 @@ + + + + + diff --git a/src/modules/09_leave/interface/index/Main.ts b/src/modules/09_leave/interface/index/Main.ts index 41766e80f..9381abe9c 100644 --- a/src/modules/09_leave/interface/index/Main.ts +++ b/src/modules/09_leave/interface/index/Main.ts @@ -68,6 +68,8 @@ interface DataSpecialTime { statusSort: number; timeAfternoon: string; timeMorning: string; + checkInStatusMain: string; + checkOutStatusMain: string; } export type { DataOption, diff --git a/src/modules/09_leave/views/04_SpecialTimeMain.vue b/src/modules/09_leave/views/04_SpecialTimeMain.vue index 1ea9ec44b..5c7890cdf 100644 --- a/src/modules/09_leave/views/04_SpecialTimeMain.vue +++ b/src/modules/09_leave/views/04_SpecialTimeMain.vue @@ -17,6 +17,7 @@ import type { import DialogReason from "@/components/Dialogs/PopupReason.vue"; import DialogApprove from "@/modules/09_leave/components/04_SpecialTime/DialogApprove.vue"; +import DialogMultipleApprove from "@/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue"; const $q = useQuasar(); // show dialog const mixin = useCounterMixin(); @@ -47,6 +48,7 @@ const name = ref(""); const id = ref(""); const dateDialog = ref(""); const dateFixDialog = ref(""); +const modalMultiple = ref(false); // ค้นหาในตาราง const filterKeyword = ref(""); @@ -54,7 +56,7 @@ const filterStatus = ref("PENDING"); const filterDate = ref<[Date, Date] | null>([new Date(), new Date()]); //วันที่ประกาศ const optionStatus = ref(store.optionStatusMain); const rows = ref([]); -const visibleColumns = ref([ +const visibleColumns = ref([ "no", "fullName", "createdAt", @@ -283,6 +285,20 @@ onMounted(async () => { From c49669021a3531e2ae5e82b9c02fcd0a90dd0074 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Tue, 23 Jun 2026 13:59:17 +0700 Subject: [PATCH 13/38] feat(notification): add delete notification feature --- .../04_SpecialTime/DialogMultipleApprove.vue | 1 + src/views/MainLayout.vue | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue b/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue index 54484d7bd..3c7051a75 100644 --- a/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue +++ b/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue @@ -105,6 +105,7 @@ function onSubmit() { dialogMessageNotify($q, "กรุณาเลือกอย่างน้อย 1 รายการ"); } else { dialogConfirm($q, async () => { + showLoader(); const payload = selected.value.map((e: DataSpecialTime) => ({ recId: e.id, checkInTime: e.checkInTime, diff --git a/src/views/MainLayout.vue b/src/views/MainLayout.vue index 33e733b0b..67af7375f 100644 --- a/src/views/MainLayout.vue +++ b/src/views/MainLayout.vue @@ -561,6 +561,26 @@ function getImg(id: string, pathName: string) { function onViewDetailNoti(url: string) { window.open(url, "_blank"); } + +function handleDeleteNotification() { + dialogRemove( + $q, + async () => { + try { + showLoader(); + await http.delete(config.API.msgNotificate); + await getDataNotification(1, "DEL"); + success($q, "ลบข้อมูลสำเร็จ"); + } catch (error) { + messageError($q, error); + } finally { + hideLoader(); + } + }, + "ยืนยันการลบข้อมูล", + "ต้องการยืนยันการลบรายการแจ้งเตือนทั้งหมดใช่หรือไม่?" + ); +} @@ -642,6 +662,17 @@ function onViewDetailNoti(url: string) {
ทั้งหมด {{ totalInbox }} ข้อความ
+ + ลบการแจ้งเตือนทั้งหมด +
Date: Tue, 23 Jun 2026 14:31:13 +0700 Subject: [PATCH 14/38] fix --- .../components/04_SpecialTime/DialogMultipleApprove.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue b/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue index 3c7051a75..b5f80c66e 100644 --- a/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue +++ b/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue @@ -164,8 +164,8 @@ watch(modal, async (val) => {
-
-
+
+
{
-
+
Date: Tue, 23 Jun 2026 14:33:12 +0700 Subject: [PATCH 15/38] Revert "fix" This reverts commit 1afe3936bd2fe07b738e1b269dfa03e65c94297c. --- .../components/04_SpecialTime/DialogMultipleApprove.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue b/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue index b5f80c66e..3c7051a75 100644 --- a/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue +++ b/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue @@ -164,8 +164,8 @@ watch(modal, async (val) => {
-
-
+
+
{
-
+
Date: Tue, 23 Jun 2026 14:40:50 +0700 Subject: [PATCH 16/38] fix --- .../components/04_SpecialTime/DialogMultipleApprove.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue b/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue index 3c7051a75..b5f80c66e 100644 --- a/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue +++ b/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue @@ -164,8 +164,8 @@ watch(modal, async (val) => {
-
-
+
+
{
-
+
Date: Tue, 23 Jun 2026 15:27:42 +0700 Subject: [PATCH 17/38] refactor(timestamp-special): update checkIn/checkOut payload and edit conditions --- .../04_SpecialTime/DialogApprove.vue | 4 +- .../04_SpecialTime/DialogMultipleApprove.vue | 42 +++++++++++++------ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/modules/09_leave/components/04_SpecialTime/DialogApprove.vue b/src/modules/09_leave/components/04_SpecialTime/DialogApprove.vue index 2eb7b2cd0..af47e1dcf 100644 --- a/src/modules/09_leave/components/04_SpecialTime/DialogApprove.vue +++ b/src/modules/09_leave/components/04_SpecialTime/DialogApprove.vue @@ -96,8 +96,8 @@ watch( formData.checkOut = ""; formData.note = ""; } else if (props.editCheck === "PENDING") { - if (props.detailData) { - if (props.detailData.checkInEdit) { + if (props.detailData) { + if (props.detailData.checkInEdit && props.detailData.checkOutEdit) { formData.checkIn = props.detailData.startTimeMorning; formData.checkOut = props.detailData.endTimeAfternoon; } else if ( diff --git a/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue b/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue index b5f80c66e..0caf9f339 100644 --- a/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue +++ b/src/modules/09_leave/components/04_SpecialTime/DialogMultipleApprove.vue @@ -106,14 +106,33 @@ function onSubmit() { } else { dialogConfirm($q, async () => { showLoader(); - const payload = selected.value.map((e: DataSpecialTime) => ({ - recId: e.id, - checkInTime: e.checkInTime, - checkOutTime: e.checkOutTime, - checkInStatus: e.checkInEdit ? "NORMAL" : e.checkInStatusMain, - checkOutStatus: e.checkOutEdit ? "NORMAL" : e.checkOutStatusMain, - reason: reason.value, - })); + const payload = selected.value.map((e: DataSpecialTime) => { + let checkInTime: string; + let checkOutTime: string; + + if (e.checkInEdit && e.checkOutEdit) { + checkInTime = e.startTimeMorning; + checkOutTime = e.endTimeAfternoon; + } else if (e.checkInEdit && !e.checkOutEdit) { + checkInTime = e.startTimeMorning; + checkOutTime = e.endTimeMorning; + } else if (!e.checkInEdit && e.checkOutEdit) { + checkInTime = e.startTimeAfternoon; + checkOutTime = e.endTimeAfternoon; + } else { + checkInTime = e.checkInTime; + checkOutTime = e.checkOutTime; + } + + return { + recId: e.id, + checkInTime, + checkOutTime, + checkInStatus: e.checkInEdit ? "NORMAL" : e.checkInStatusMain, + checkOutStatus: e.checkOutEdit ? "NORMAL" : e.checkOutStatusMain, + reason: reason.value, + }; + }); try { await http.put(config.API.specialTimeApproveLists, payload); @@ -236,7 +255,9 @@ watch(modal, async (val) => {
- + *หมายเหตุเลือกทั้งหมดเฉพาะรายการที่แสดงเท่านั้น
{ rows="3" />
- *หมายเหตุเลือกทั้งหมดเฉพาะรายการที่แสดงเท่านั้น From c0aa2856759f51ce7e89ba00e671ac9fcb500ee9 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Tue, 23 Jun 2026 15:54:08 +0700 Subject: [PATCH 18/38] refactor(notification): update icon and text display --- src/views/MainLayout.vue | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/views/MainLayout.vue b/src/views/MainLayout.vue index 67af7375f..5c336f0f8 100644 --- a/src/views/MainLayout.vue +++ b/src/views/MainLayout.vue @@ -570,15 +570,15 @@ function handleDeleteNotification() { showLoader(); await http.delete(config.API.msgNotificate); await getDataNotification(1, "DEL"); - success($q, "ลบข้อมูลสำเร็จ"); + success($q, "รล้างการแจ้งสำเร็จ"); } catch (error) { messageError($q, error); } finally { hideLoader(); } }, - "ยืนยันการลบข้อมูล", - "ต้องการยืนยันการลบรายการแจ้งเตือนทั้งหมดใช่หรือไม่?" + "ยืนยันการล้างการแจ้งเตือนทั้งหมด", + "ต้องการยืนยันการล้างการแจ้งเตือนทั้งหมดทั้งหมดใช่หรือไม่?" ); } @@ -667,11 +667,11 @@ function handleDeleteNotification() { flat dense round - color="red" - icon="delete" + color="grey-7" + icon="mdi-trash-can-outline" @click.stop.prevent="handleDeleteNotification" > - ลบการแจ้งเตือนทั้งหมด + ล้างการแจ้งเตือนทั้งหมด
From 16c21467e49e48c820eefdd44701b7cafd16e397 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Tue, 23 Jun 2026 16:17:56 +0700 Subject: [PATCH 19/38] fix --- src/views/MainLayout.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/MainLayout.vue b/src/views/MainLayout.vue index 5c336f0f8..26b6cf9b1 100644 --- a/src/views/MainLayout.vue +++ b/src/views/MainLayout.vue @@ -578,7 +578,7 @@ function handleDeleteNotification() { } }, "ยืนยันการล้างการแจ้งเตือนทั้งหมด", - "ต้องการยืนยันการล้างการแจ้งเตือนทั้งหมดทั้งหมดใช่หรือไม่?" + "ต้องการยืนยันการล้างการแจ้งเตือนทั้งหมดใช่หรือไม่?" ); } From fd665b8b4d776e31ff8f4920139f583b562d2e09 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Thu, 25 Jun 2026 14:53:59 +0700 Subject: [PATCH 20/38] refactor(qualify): replace api CandidateExam --- src/api/recruiting/api.period-exam.ts | 5 +- .../components/TableCandidate.vue | 76 ++++++++++++------- src/views/MainLayout.vue | 2 +- 3 files changed, 54 insertions(+), 29 deletions(-) diff --git a/src/api/recruiting/api.period-exam.ts b/src/api/recruiting/api.period-exam.ts index bf777e193..470303286 100644 --- a/src/api/recruiting/api.period-exam.ts +++ b/src/api/recruiting/api.period-exam.ts @@ -98,6 +98,9 @@ export default { `${env.API_URI}/placement/candidate/pdf/${candidateId}`, downloadCandidateExam: (id: string) => - `${periodExam}download/candidate-exam/${id}`, + `${exam_report}candidate/candidate-new/${id}`, downloadPassExam: (id: string) => `${periodExam}download/pass-exam/${id}`, + + downloadCandidatePassExam: (id: string) => + `${exam_report}candidate/pass-new/${id}`, }; diff --git a/src/modules/03_recruiting/components/TableCandidate.vue b/src/modules/03_recruiting/components/TableCandidate.vue index f5b1b2b21..5df6fa66c 100644 --- a/src/modules/03_recruiting/components/TableCandidate.vue +++ b/src/modules/03_recruiting/components/TableCandidate.vue @@ -363,37 +363,59 @@ async function downloadFileDashboard() { } async function clickPassExam() { - showLoader(); - await http - .get(config.API.downloadPassExam(examId.value)) - .then(async (res) => { - const data = res.data.result; - data.reportName = `Candidate_Dashboard_${dateToISO(new Date())}`; - await genReport(data, data.reportName, "pdf"); - }) - .catch((e) => { - messageError($q, e); - }) - .finally(() => { - hideLoader(); - }); + try { + showLoader(); + const res = await http.get( + config.API.downloadCandidatePassExam(examId.value), + { + headers: { + "Content-Type": "application/pdf", + Accept: "application/pdf", + }, + responseType: "blob", + } + ); + const url = window.URL.createObjectURL(new Blob([res.data])); + const link = document.createElement("a"); + link.href = url; + link.setAttribute( + "download", + `Candidate_Dashboard_${dateToISO(new Date())}` + ".pdf" + ); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + window.URL.revokeObjectURL(url); + } catch (error) { + messageError($q); + } finally { + hideLoader(); + } } async function clickCandidateList() { - showLoader(); - await http - .get(config.API.downloadCandidateExam(examId.value)) - .then(async (res) => { - const data = res.data.result; - data.reportName = `Candidate_Dashboard_${dateToISO(new Date())}`; - await genReport(data, data.reportName, "pdf"); - }) - .catch((e) => { - messageError($q, e); - }) - .finally(() => { - hideLoader(); + try { + showLoader(); + const res = await http.get(config.API.downloadCandidateExam(examId.value), { + headers: { + "Content-Type": "application/pdf", + Accept: "application/pdf", + }, + responseType: "blob", }); + const url = window.URL.createObjectURL(new Blob([res.data])); + const link = document.createElement("a"); + link.href = url; + link.setAttribute("download", "รายชื่อผู้มีสิทธิ์สอบ" + ".pdf"); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + window.URL.revokeObjectURL(url); + } catch (error) { + messageError($q); + } finally { + hideLoader(); + } } async function onCheckShowExaminfo() { diff --git a/src/views/MainLayout.vue b/src/views/MainLayout.vue index 26b6cf9b1..b37c2b183 100644 --- a/src/views/MainLayout.vue +++ b/src/views/MainLayout.vue @@ -570,7 +570,7 @@ function handleDeleteNotification() { showLoader(); await http.delete(config.API.msgNotificate); await getDataNotification(1, "DEL"); - success($q, "รล้างการแจ้งสำเร็จ"); + success($q, "ล้างการแจ้งสำเร็จ"); } catch (error) { messageError($q, error); } finally { From a9bef5bc42f418ebbcb2d8c47d2bc64638b84faf Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Thu, 25 Jun 2026 17:19:10 +0700 Subject: [PATCH 21/38] fix --- src/modules/03_recruiting/components/TableCandidate.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/03_recruiting/components/TableCandidate.vue b/src/modules/03_recruiting/components/TableCandidate.vue index 5df6fa66c..5ff53b467 100644 --- a/src/modules/03_recruiting/components/TableCandidate.vue +++ b/src/modules/03_recruiting/components/TableCandidate.vue @@ -387,7 +387,7 @@ async function clickPassExam() { document.body.removeChild(link); window.URL.revokeObjectURL(url); } catch (error) { - messageError($q); + messageError($q, error); } finally { hideLoader(); } @@ -412,7 +412,7 @@ async function clickCandidateList() { document.body.removeChild(link); window.URL.revokeObjectURL(url); } catch (error) { - messageError($q); + messageError($q, error); } finally { hideLoader(); } From 44e60d457fdfb920151d05b4f0afcceab1705165 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Thu, 25 Jun 2026 18:01:45 +0700 Subject: [PATCH 22/38] fix --- .../03_recruiting/components/TableCandidate.vue | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/modules/03_recruiting/components/TableCandidate.vue b/src/modules/03_recruiting/components/TableCandidate.vue index 5ff53b467..d725a3bc1 100644 --- a/src/modules/03_recruiting/components/TableCandidate.vue +++ b/src/modules/03_recruiting/components/TableCandidate.vue @@ -571,8 +571,20 @@ watch(
- - ดาวน์โหลดไฟล์ + + + {{ + attrs.rows.length !== 0 + ? "ดาวน์โหลดไฟล์" + : "ไม่มีข้อมูลผู้สอบคัดเลือก" + }}
diff --git a/src/modules/05_placement/components/PersonalList/DialogDetail.vue b/src/modules/05_placement/components/PersonalList/DialogDetail.vue index 13aa09aef..dff09ffdd 100644 --- a/src/modules/05_placement/components/PersonalList/DialogDetail.vue +++ b/src/modules/05_placement/components/PersonalList/DialogDetail.vue @@ -525,14 +525,14 @@ watch(props, () => {
ผลการสอบ
ลำดับที่สอบได้
-
จำนวนครั้งที่สมัครสอบ
+
{{ personalForm?.pass }}
{{ personalForm?.examNumber }}
-
{{ personalForm?.examRound }}
+
From 2355639f2552adec59ce4dae0909233791ce34be Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Mon, 29 Jun 2026 15:27:25 +0700 Subject: [PATCH 26/38] Revert "refactor: disable DonwloadCandidatePassExam" This reverts commit 6e8dbfc37556ff5c8c6bb2aa1e5728c1a7d90a9c. --- .../03_recruiting/components/TableCandidate.vue | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/modules/03_recruiting/components/TableCandidate.vue b/src/modules/03_recruiting/components/TableCandidate.vue index bd0dd72fe..d725a3bc1 100644 --- a/src/modules/03_recruiting/components/TableCandidate.vue +++ b/src/modules/03_recruiting/components/TableCandidate.vue @@ -1,5 +1,5 @@ + + + + diff --git a/src/modules/09_leave/interface/response/work.ts b/src/modules/09_leave/interface/response/work.ts index af055b794..d35a1a8d4 100644 --- a/src/modules/09_leave/interface/response/work.ts +++ b/src/modules/09_leave/interface/response/work.ts @@ -98,6 +98,26 @@ interface DataProcess { errorMessage: string | null; } +interface DataPendingJobs { + taskId: string; + keycloakUserId: string; + createdDate: string | Date; + processingDate: string | Date; + completedDate: string | Date; + status: string; + checkType: string; + checkInId: string; + errorMessage: string; + additionalData: string; + id: string; + createdAt: string | Date; + createdUserId: string; + lastUpdatedAt: string; + lastUpdateUserId: string; + createdFullName: string; + lastUpdateFullName: string; +} + export type { TableRows, DataResLog, @@ -105,4 +125,5 @@ export type { TableRowsTime, FormDetail, DataProcess, + DataPendingJobs, }; diff --git a/src/modules/09_leave/views/02_WorkingMain.vue b/src/modules/09_leave/views/02_WorkingMain.vue index fed615baf..87b81c060 100644 --- a/src/modules/09_leave/views/02_WorkingMain.vue +++ b/src/modules/09_leave/views/02_WorkingMain.vue @@ -9,6 +9,7 @@ import { useRoute } from "vue-router"; import Tab1 from "@/modules/09_leave/components/02_WorkList/Tab1.vue"; import Tab2 from "@/modules/09_leave/components/02_WorkList/Tab2.vue"; import Tab3 from "@/modules/09_leave/components/02_WorkList/Tab3_Processed_Late.vue"; +import Tab4_Pending from "@/modules/09_leave/components/02_WorkList/Tab4_Pending.vue"; const stores = useWorklistDataStore(); const route = useRoute(); @@ -21,6 +22,10 @@ const isPermissionTab3 = computed(() => { checkPermission(route)?.attrIsUpdate) ); }); + +const isPermissionTab4 = computed(() => { + return checkPermission(route)?.attrOwnership === "OWNER"; +});