From 999a2d1b4568ebcb3e68dbbe5e89e2dfa103cb1a Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Tue, 5 May 2026 17:39:52 +0700 Subject: [PATCH 01/46] refactor(DialogOrgSelect): reset positionData to default values --- src/components/Dialogs/DialogOrgSelect.vue | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/components/Dialogs/DialogOrgSelect.vue b/src/components/Dialogs/DialogOrgSelect.vue index af860b60e..b6a4ed6ae 100644 --- a/src/components/Dialogs/DialogOrgSelect.vue +++ b/src/components/Dialogs/DialogOrgSelect.vue @@ -244,10 +244,16 @@ function close() { expanded.value = []; nodeLevel.value = 0; nodeId.value = ""; + positionData.value = []; + positionNo.value = []; + rowData.value = []; } async function getDataTable(id: string, level: number = 0) { showLoader(); + positionData.value = []; + positionNo.value = []; + rowData.value = []; const body = { node: level, nodeId: id, @@ -261,7 +267,7 @@ async function getDataTable(id: string, level: number = 0) { await http .post(config.API.orgPosPlacement, body) - .then((res) => { + .then(async (res) => { const dataMain: PositionMain[] = []; posMasterMain.value = res.data.result.data; @@ -299,7 +305,6 @@ async function getDataTable(id: string, level: number = 0) { positionNo.value = listPosNo; rowData.value = listPosNo; - // positionData.value = listPosNo; if (props.dataRows?.posmasterId) { const newUse = positionUse.value.filter( @@ -313,6 +318,7 @@ async function getDataTable(id: string, level: number = 0) { (e: any) => !positionUse.value.includes(e.id) ); } + await onClickSelectPos(positionId.value); }) .catch((err) => { messageError($q, err); @@ -409,7 +415,6 @@ async function fetchPosFind(level: number, id: string) { seletcId.value = props?.dataRows?.positionId; datePos.value = props?.dataRows?.reportingDate; await getDataTable(nodeId.value, level); - await onClickSelectPos(positionId.value); }) .catch((e) => { messageError($q, e); From e513586b65471e6418fcb350b42df922afe04640 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Wed, 6 May 2026 09:39:53 +0700 Subject: [PATCH 02/46] refactor(DialogOrgSelect): fetch data --- src/components/Dialogs/DialogOrgSelect.vue | 106 +++++++++++---------- 1 file changed, 55 insertions(+), 51 deletions(-) diff --git a/src/components/Dialogs/DialogOrgSelect.vue b/src/components/Dialogs/DialogOrgSelect.vue index b6a4ed6ae..8acabf448 100644 --- a/src/components/Dialogs/DialogOrgSelect.vue +++ b/src/components/Dialogs/DialogOrgSelect.vue @@ -24,14 +24,14 @@ import DialogHeader from "@/components/DialogHeader.vue"; const props = defineProps({ dataRows: { type: Object, - require: true, + required: true, }, onSubmit: Function, }); const $q = useQuasar(); const route = useRoute(); const storeTree = useStructureTree(); -const { fetchStructureTree } = useStructureTree(); +const { fetchStructureTree } = storeTree; const mixin = useCounterMixin(); const { dialogConfirm, @@ -47,10 +47,10 @@ const { /** props*/ const modal = defineModel("modal", { required: true }); const title = defineModel("title", { required: true }); -const type = defineModel("type", { required: true }); -const posType = defineModel("posType", { required: true }); -const posLevel = defineModel("posLevel", { required: true }); -const position = defineModel("position", { required: true }); +const type = defineModel("type", { required: true }); +const posType = defineModel("posType", { required: true }); +const posLevel = defineModel("posLevel", { required: true }); +const position = defineModel("position", { required: true }); // const routeName = ref(route?.name); const orgRevisionId = ref(""); @@ -64,7 +64,7 @@ const itemTaps = ref(); const filters = ref(""); const positionId = ref(""); const selectedPos = ref([]); -const seletcId = ref(""); +const selectId = ref(""); const datePos = ref(new Date()); const rowsPosition = ref([]); const positionData = ref([]); @@ -79,7 +79,6 @@ const formActive = reactive({ }); /** node */ const nodes = ref>([]); -const lazy = ref(nodes); const expanded = ref([]); const nodeLevel = ref(0); const nodeId = ref(""); // id ของ Tree @@ -150,7 +149,7 @@ const columns = ref([ style: "font-size: 14px", }, ]); -const columnsPostition = ref([ +const columnsPosition = ref([ { name: "no", align: "left", @@ -181,7 +180,7 @@ const columnsPostition = ref([ { name: "posTypeName", align: "left", - label: "ประเภทตำเเหน่ง", + label: "ประเภทตำแหน่ง", sortable: true, field: "posTypeName", headerStyle: "font-size: 14px", @@ -335,11 +334,11 @@ async function getDataTable(id: string, level: number = 0) { function updateSelected(data: DataTree) { if (props?.dataRows?.nodeId === data.orgTreeId) { positionId.value = props?.dataRows?.posmasterId; - seletcId.value = props?.dataRows?.positionId; + selectId.value = props?.dataRows?.positionId; datePos.value = props?.dataRows?.reportingDate; } else { positionId.value = ""; - seletcId.value = ""; + selectId.value = ""; selectedPos.value = []; datePos.value = new Date(); } @@ -386,9 +385,9 @@ async function onClickSelectPos(id: string) { // หาตำแหน่ง if (position) { rowsPosition.value = position.positions; - if (seletcId.value) { + if (selectId.value) { selectedPos.value = rowsPosition.value.filter( - (e) => e.id === seletcId.value + (e) => e.id === selectId.value ); } } @@ -412,12 +411,14 @@ async function fetchPosFind(level: number, id: string) { expanded.value = data; nodeId.value = id; positionId.value = props?.dataRows?.posmasterId; - seletcId.value = props?.dataRows?.positionId; + selectId.value = props?.dataRows?.positionId; datePos.value = props?.dataRows?.reportingDate; await getDataTable(nodeId.value, level); }) .catch((e) => { messageError($q, e); + }) + .finally(() => { hideLoader(); }); } @@ -461,19 +462,15 @@ function fetchPositionUes() { watch( () => isAll.value, - (value, oldVal) => { - if (value !== oldVal) { - getDataTable(nodeId.value, nodeLevel.value); - } + () => { + getDataTable(nodeId.value, nodeLevel.value); } ); watch( () => isBlank.value, - (value, oldVal) => { - if (value !== oldVal) { - getDataTable(nodeId.value, nodeLevel.value); - } + () => { + getDataTable(nodeId.value, nodeLevel.value); } ); @@ -489,35 +486,42 @@ function onSubmit() { const dataPosMaster = posMasterMain.value?.find( (e: any) => e.id === positionId.value ); + + if (!dataPosMaster) { + dialogMessageNotify($q, "ไม่พบข้อมูลตำแหน่ง"); + return; + } + if (selectedPos.value.length === 0) { dialogMessageNotify($q, "กรุณาเลือกตำแหน่ง"); - } else { - dialogConfirm($q, async () => { - const body = { - personalId: props?.dataRows?.id, - node: dataPosMaster.node, - nodeId: dataPosMaster.nodeId, - orgRevisionId: formActive.activeId, - positionId: selectedPos.value[0].id, - posMasterNo: dataPosMaster.posMasterNo, //ตำแหน่งเลขที่(เลขอย่่างเดียว) - positionName: selectedPos.value[0].positionName, //ชื่อตำแหน่ง - positionField: selectedPos.value[0].positionField, //ชื่อตำแหน่ง - posTypeId: selectedPos.value[0].posTypeId, //ชื่อตำแหน่ง - posTypeName: selectedPos.value[0].posTypeName, //ชื่อตำแหน่ง - posLevelId: selectedPos.value[0].posLevelId, //ชื่อตำแหน่ง - posLevelName: selectedPos.value[0].posLevelName, //ชื่อตำแหน่ง - posExecutiveName: selectedPos.value[0].posExecutiveName, //ชื่อตำแหน่ง - reportingDate: convertDateToAPI(datePos.value), - posmasterId: dataPosMaster.id, - typeCommand: type.value, - positionExecutiveField: selectedPos.value[0].positionExecutiveField, //ด้านทางการบริหาร - positionArea: selectedPos.value[0].positionArea, //ด้าน/สาขา - }; - - await props.onSubmit?.(body); - close(); - }); + return; } + + dialogConfirm($q, async () => { + const body = { + personalId: props?.dataRows?.id, + node: dataPosMaster.node, + nodeId: dataPosMaster.nodeId, + orgRevisionId: formActive.activeId, + positionId: selectedPos.value[0].id, + posMasterNo: dataPosMaster.posMasterNo, //ตำแหน่งเลขที่(เลขอย่่างเดียว) + positionName: selectedPos.value[0].positionName, //ชื่อตำแหน่ง + positionField: selectedPos.value[0].positionField, //ชื่อตำแหน่ง + posTypeId: selectedPos.value[0].posTypeId, //ชื่อตำแหน่ง + posTypeName: selectedPos.value[0].posTypeName, //ชื่อตำแหน่ง + posLevelId: selectedPos.value[0].posLevelId, //ชื่อตำแหน่ง + posLevelName: selectedPos.value[0].posLevelName, //ชื่อตำแหน่ง + posExecutiveName: selectedPos.value[0].posExecutiveName, //ชื่อตำแหน่ง + reportingDate: convertDateToAPI(datePos.value), + posmasterId: dataPosMaster.id, + typeCommand: type.value, + positionExecutiveField: selectedPos.value[0].positionExecutiveField, //ด้านทางการบริหาร + positionArea: selectedPos.value[0].positionArea, //ด้าน/สาขา + }; + + await props.onSubmit?.(body); + close(); + }); } function onSearch() { @@ -564,7 +568,7 @@ onMounted(async () => { { Date: Wed, 6 May 2026 09:48:19 +0700 Subject: [PATCH 03/46] fix --- src/components/Dialogs/DialogOrgSelect.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Dialogs/DialogOrgSelect.vue b/src/components/Dialogs/DialogOrgSelect.vue index 8acabf448..e3c5e4634 100644 --- a/src/components/Dialogs/DialogOrgSelect.vue +++ b/src/components/Dialogs/DialogOrgSelect.vue @@ -24,7 +24,7 @@ import DialogHeader from "@/components/DialogHeader.vue"; const props = defineProps({ dataRows: { type: Object, - required: true, + default: () => ({}), }, onSubmit: Function, }); From 5ac50fc1f2c4f702985c1019400a76fef9ce6121 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Wed, 6 May 2026 10:53:53 +0700 Subject: [PATCH 04/46] refactor(placement): PersonalList DialogSelectOrg --- .../components/PersonalList/CardPosition.vue | 6 +- .../PersonalList/DialogSelectOrg.vue | 85 ++++++++----------- 2 files changed, 39 insertions(+), 52 deletions(-) diff --git a/src/modules/05_placement/components/PersonalList/CardPosition.vue b/src/modules/05_placement/components/PersonalList/CardPosition.vue index 70b0b117d..a4e1f18b7 100644 --- a/src/modules/05_placement/components/PersonalList/CardPosition.vue +++ b/src/modules/05_placement/components/PersonalList/CardPosition.vue @@ -22,7 +22,7 @@ const store = useSelectOrgStore(); /** props*/ const selected = defineModel("selectedPos", { required: true }); //ตำแหน่งที่เลือก const positionId = defineModel("positionId", { required: true }); //id ตำแหน่งที่เลือก -const seletcId = defineModel("seletcId", { required: true }); // ตำแหน่งที่เลือก +const selectId = defineModel("selectId", { required: true }); // ตำแหน่งที่เลือก const date = defineModel("datePos", { required: true }); //วันยที่รายงานคัว const positionData = defineModel("position", { required: true }); //ข้อมูลรายการเลขที่ตำแหน่ง const isAll = defineModel("isAll", { required: true }); //แสดงตำแหน่งทั้งหมด @@ -214,9 +214,9 @@ async function onClickSelectPos(id: string) { // หาตำแหน่ง if (position) { rowsPosition.value = position.positions; - if (seletcId.value) { + if (selectId.value) { selected.value = rowsPosition.value.filter( - (e) => e.id === seletcId.value + (e) => e.id === selectId.value ); } } diff --git a/src/modules/05_placement/components/PersonalList/DialogSelectOrg.vue b/src/modules/05_placement/components/PersonalList/DialogSelectOrg.vue index 2eb316763..e54741069 100644 --- a/src/modules/05_placement/components/PersonalList/DialogSelectOrg.vue +++ b/src/modules/05_placement/components/PersonalList/DialogSelectOrg.vue @@ -11,6 +11,7 @@ import { useStructureTree } from "@/stores/structureTree"; /** importType*/ import type { + DataList, PositionMaim, PositionNo, Positions, @@ -41,17 +42,14 @@ const { /**props*/ const modal = defineModel("modal", { required: true }); -const props = defineProps({ - dataRow: { - type: Object, - require: true, - }, - fetchTable: { - type: Function, - require: true, - }, - fetchStatCard: { type: Function, require: true }, -}); + +interface Props { + dataRow?: DataList; + fetchTable?: () => Promise; + fetchStatCard?: () => Promise; +} + +const props = defineProps(); /** Tree*/ const nodeId = ref(""); @@ -65,12 +63,12 @@ const expanded = ref([]); const positionUse = ref([]); const positionNo = ref([]); const positionId = ref(""); -const seletcId = ref(""); +const selectId = ref(""); const posType = ref(null); const posLevel = ref(""); -const selectedPos = ref([]); +const selectedPos = ref([]); const datePos = ref(new Date()); -const posMasterMain = ref([]); +const posMasterMain = ref([]); const orgRevisionId = ref(""); const optionPosType = ref([]); const optionPosLevel = ref([]); @@ -92,14 +90,14 @@ async function fetchStructure() { */ function updateSelected(data: TreeMain) { if (props?.dataRow?.nodeId === data.orgTreeId) { - positionId.value = props?.dataRow?.posmasterId; - seletcId.value = props?.dataRow?.positionId; + positionId.value = props?.dataRow?.posmasterId ?? ""; + selectId.value = props?.dataRow?.positionId ?? ""; datePos.value = props?.dataRow?.reportingDate ? new Date(props.dataRow.reportingDate) : new Date(); } else { positionId.value = ""; - seletcId.value = ""; + selectId.value = ""; selectedPos.value = []; datePos.value = new Date(); } @@ -155,7 +153,7 @@ async function fetchDataTable(id: string, level: number = 0) { if (p.length !== 0) { const a = p.find((el: Positions) => el.positionIsSelected === true); const { id, ...rest } = a ? a : p[0]; - const data: any = { ...e, ...rest }; + const data: PositionMaim = { ...e, ...rest } as PositionMaim; dataMain.push(data); } }); @@ -167,10 +165,10 @@ async function fetchDataTable(id: string, level: number = 0) { (e) => e !== props.dataRow?.posmasterId ); - positionNo.value = posMain.filter((e: any) => !newUse.includes(e.id)); + positionNo.value = posMain.filter((e: DataPositionNo) => !newUse.includes(e.id)); } else { positionNo.value = posMain.filter( - (e: any) => !positionUse.value.includes(e.id) + (e: DataPositionNo) => !positionUse.value.includes(e.id) ); } @@ -202,8 +200,8 @@ async function fetchPosFind(level: number, id: string) { expanded.value = data; nodeId.value = id; - positionId.value = props?.dataRow?.posmasterId; - seletcId.value = props?.dataRow?.positionId; + positionId.value = props?.dataRow?.posmasterId ?? ""; + selectId.value = props?.dataRow?.positionId ?? ""; datePos.value = props?.dataRow?.reportingDate ? new Date(props.dataRow.reportingDate) : new Date(); @@ -218,12 +216,14 @@ async function fetchPosFind(level: number, id: string) { /** function บันทึกข้อมูลตำแหน่ง*/ async function onClickSubmit() { - const dataPosMaster = await posMasterMain.value?.find( - (e: any) => e.id === positionId.value + const dataPosMaster = posMasterMain.value?.find( + (e) => e.id === positionId.value ); if (selectedPos.value.length === 0) { dialogMessageNotify($q, "กรุณาเลือกตำแหน่ง"); + } else if (!dataPosMaster) { + dialogMessageNotify($q, "ไม่พบข้อมูลตำแหน่ง"); } else { dialogConfirm($q, async () => { showLoader(); @@ -290,7 +290,7 @@ watch( if (modal.value) { await fetchPositionUes(); if (props?.dataRow?.node !== null && props?.dataRow?.nodeId !== null) { - await fetchPosFind(props?.dataRow?.node, props?.dataRow?.nodeId); + await fetchPosFind(props?.dataRow?.node ?? 0, props?.dataRow?.nodeId ?? ""); } else { expanded.value = []; } @@ -343,28 +343,15 @@ function onPosType() { } watch( - () => isAll.value, - (value, oldVal) => { - if (value !== oldVal) { + [isAll, isBlank, () => isPosition.value], + ([newAll, newBlank, newPos], [oldAll, oldBlank, oldPos]) => { + const shouldFetch = (newAll !== oldAll) || (newBlank !== oldBlank); + const isSelectMode = newPos === "select" && oldPos !== "select"; + + if (shouldFetch || isSelectMode) { fetchDataTable(nodeId.value, nodeLevel.value); } - } -); - -watch( - () => isBlank.value, - (value, oldVal) => { - if (value !== oldVal) { - fetchDataTable(nodeId.value, nodeLevel.value); - } - } -); - -watch( - () => isPosition.value === "select", - (value, oldVal) => { - if (value !== oldVal) { - fetchDataTable(nodeId.value, nodeLevel.value); + if (isSelectMode) { getOrgPosType(); } } @@ -465,15 +452,15 @@ onMounted(() => { :name="item" > { :on-pos-type="onPosType" :node-id="nodeId" :node-level="nodeLevel" - :bma-officer="props.dataRow?.bmaOfficer" + :bma-officer="props.dataRow?.bmaOfficer ?? ''" :is-load-position="isLoadPosition" /> From 29b45f77ea882dfc2890b16cfafa6dd97c884b39 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Wed, 6 May 2026 10:54:37 +0700 Subject: [PATCH 05/46] refactor(placement): interface DataList --- src/modules/05_placement/interface/response/SelectOrg.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/modules/05_placement/interface/response/SelectOrg.ts b/src/modules/05_placement/interface/response/SelectOrg.ts index d5fa88ed5..5e264e51e 100644 --- a/src/modules/05_placement/interface/response/SelectOrg.ts +++ b/src/modules/05_placement/interface/response/SelectOrg.ts @@ -1,17 +1,24 @@ interface DataList { avatar: string; bmaOfficer: string; + bmaOfficerCheck?: string; deferment: boolean; draft: string; examNumber: number; fullName: string; idCard: string; name: string; + node: number | null; + nodeId: string | null; orgName: string | null; organizationName: string; organizationShortName: string | null; personalId: string; + posLevelCandidateId: string | null; + posmasterId: string | null; + posTypeCandidateId: string | null; positionCandidate: string; + positionId: string | null; positionNumber: string | null; positionPath: string | null; profilePhoto: string; From 0739f2b9d7ffdb2a7c45b2b6526ba5ee9150fc42 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Thu, 7 May 2026 10:40:58 +0700 Subject: [PATCH 06/46] feat(receive): add input rank --- .../components/Receive/ReceiveAddPerson.vue | 72 ++++++++++++++++--- .../components/Receive/receiveDetail.vue | 68 +++++++++++++++++- .../interface/index/ProfileType.ts | 3 + 3 files changed, 132 insertions(+), 11 deletions(-) diff --git a/src/modules/05_placement/components/Receive/ReceiveAddPerson.vue b/src/modules/05_placement/components/Receive/ReceiveAddPerson.vue index e6d2da0ce..fa0551e99 100644 --- a/src/modules/05_placement/components/Receive/ReceiveAddPerson.vue +++ b/src/modules/05_placement/components/Receive/ReceiveAddPerson.vue @@ -48,6 +48,7 @@ const informaData = ref({ employeeType: null, employeeClass: null, profileType: null, + rank: "", }); // รายการข้อมูลทั้งหมด @@ -60,6 +61,7 @@ const Ops = ref({ religionOps: [], employeeClassOps: [], employeeTypeOps: [], + rankOps: [], }); // ข้อมูลเมื่อเลือกแล้ว const OpsFilter = ref({ @@ -71,6 +73,7 @@ const OpsFilter = ref({ religionOps: [], employeeClassOps: [], employeeTypeOps: [], + rankOps: [], }); // รูป profile @@ -135,6 +138,16 @@ async function fetchPerson() { }); Ops.value.religionOps = optionreligions; OpsFilter.value.religionOps = optionreligions; + + let rank: DataOption[] = []; + data.rank.map((r: DataOptioninfo) => { + rank.push({ + id: r.id.toString(), + name: r.name.toString(), + }); + }); + Ops.value.rankOps = rank; + OpsFilter.value.rankOps = rank; }) .catch((e) => { messageError($q, e); @@ -204,7 +217,13 @@ function filterSelector(val: string, update: Function, refData: string) { ); }); break; - + case "rankOps": + update(() => { + Ops.value.rankOps = OpsFilter.value.rankOps.filter( + (v: DataOption) => v.name.toLowerCase().indexOf(newVal) > -1 + ); + }); + break; default: break; } @@ -227,7 +246,7 @@ function onSubmit() { if (fileData.value != null) formData.append("File", fileData.value); //แก้ไขรูป if (informaData.value.citizenId != undefined) formData.append("citizenId", informaData.value.citizenId); - if (informaData.value.prefix != undefined) + if (informaData.value.prefix != undefined && informaData.value.prefix != "") formData.append("prefix", informaData.value.prefix); if (informaData.value.firstName != undefined) formData.append("firstName", informaData.value.firstName); @@ -256,6 +275,8 @@ function onSubmit() { formData.append("employeeType", informaData.value.employeeType); if (informaData.value.employeeClass != undefined) formData.append("employeeClass", informaData.value.employeeClass); + if (informaData.value.rank != undefined && informaData.value.rank != "") + formData.append("rank", informaData.value.rank); dialogConfirm($q, async () => { showLoader(); @@ -289,6 +310,15 @@ function updateBirthDate(v: Date) { age.value = calculateAge(v); } +function prefixRankRule() { + return [ + () => + !!informaData.value.rank || + !!informaData.value.prefix || + "กรุณาเลือกคำนำหน้าชื่อ หรือยศ", + ]; +} + /** * ทำงานเมื่อมีการเรียกใช้ Components */ @@ -383,7 +413,7 @@ onMounted(async () => {
-
+
{ mask="#############" />
-
+
{ option-value="name" map-options hide-bottom-space - :rules="[ - (val:string) => { - return val.length > 0 || 'กรุณาเลือกคำนำหน้าชื่อ'; - }, - ]" + :rules="prefixRankRule()" + reactive-rules emit-value use-input hide-selected @@ -432,6 +460,32 @@ onMounted(async () => { )" />
+
+ +
({ { id: "gov", name: "งบประมาณเงินอุดหนุนรัฐบาล" }, { id: "bkk", name: "งบประมาณกรุงเทพมหานคร" }, ], + rankOps: [], }); const OpsFilter = ref({ prefixOps: [], @@ -129,6 +130,7 @@ const OpsFilter = ref({ { id: "gov", name: "งบประมาณเงินอุดหนุนรัฐบาล" }, { id: "bkk", name: "งบประมาณกรุงเทพมหานคร" }, ], + rankOps: [], }); /** ฟังก์ชันดึงข้อมูลรายการข้อมูลเกี่ยวกับบุคคล (dropdown list)*/ @@ -186,6 +188,16 @@ async function fetchPerson() { }); Ops.value.religionOps = optionreligions; OpsFilter.value.religionOps = optionreligions; + + let rank: DataOption[] = []; + data.rank.map((r: DataOptioninfo) => { + rank.push({ + id: r.id.toString(), + name: r.name.toString(), + }); + }); + Ops.value.rankOps = rank; + OpsFilter.value.rankOps = rank; }) .catch((e) => { messageError($q, e); @@ -230,6 +242,7 @@ async function getData() { (data.prefix == "00000000-0000-0000-0000-000000000000" ? null : data.prefix) ?? "", + rank: data.rank ?? "", firstname: data.firstName ?? "", lastname: data.lastName ?? "", birthDate: @@ -295,6 +308,7 @@ async function fetchData(data: any) { (data.prefix == "00000000-0000-0000-0000-000000000000" ? null : data.prefix) ?? "", + rank: data.rank ?? "", firstname: data.firstName ?? "", lastname: data.lastName ?? "", birthDate: data.dateOfBirth !== null ? new Date(data.dateOfBirth) : null, @@ -436,6 +450,14 @@ function filterSelector(val: string, update: Function, refData: string) { }); break; + case "rankOps": + update(() => { + Ops.value.rankOps = OpsFilter.value.rankOps.filter( + (v: DataOption) => v.name.toLowerCase().indexOf(newVal) > -1 + ); + }); + break; + default: break; } @@ -470,6 +492,7 @@ function saveData() { positionNumberOld: posNo.value, amount: 0, amountOld: salary.value, + rank: informaData.value.rank, }; showLoader(); http @@ -517,6 +540,15 @@ function updateBirthDate(v: Date) { informaData.value.age = calculateAge(v); } +function prefixRankRule() { + return [ + () => + !!informaData.value.rank || + !!informaData.value.prefixId || + "กรุณาเลือกคำนำหน้าชื่อ หรือยศ", + ]; +} + /** ทำงานเมื่อมีการเรียกใช้ Components*/ onMounted(async () => { await fetchPerson(); @@ -598,7 +630,7 @@ onMounted(async () => {
ข้อมูลส่วนตัว
-
+
{ mask="#############" />
-
+
{ option-value="name" :label="`${'คำนำหน้าชื่อ'}`" use-input + clearable input-debounce="0" + :rules="prefixRankRule()" + reactive-rules @filter="(inputValue:string, doneFn:Function) => filterSelector(inputValue, doneFn,'prefixOps' ) " />
+ +
+ +
+
Date: Thu, 7 May 2026 16:24:30 +0700 Subject: [PATCH 07/46] refactor(timestamp-special): filter date and status --- .../09_leave/stores/SpecialTimeStore.ts | 10 +- .../09_leave/views/04_SpecialTimeMain.vue | 146 +++++++++++------- 2 files changed, 97 insertions(+), 59 deletions(-) diff --git a/src/modules/09_leave/stores/SpecialTimeStore.ts b/src/modules/09_leave/stores/SpecialTimeStore.ts index 4196c93b6..83024a8ef 100644 --- a/src/modules/09_leave/stores/SpecialTimeStore.ts +++ b/src/modules/09_leave/stores/SpecialTimeStore.ts @@ -11,7 +11,14 @@ export const useSpecialTimeStore = defineStore("LeaveSpecialTime", () => { { id: "NOT_COMPLETE", name: "ปฏิบัติงานไม่ครบตามกำหนดเวลา" }, ]); - // convertSatatus + const optionStatusMain = ref([ + { id: "ALL", name: "ทั้งหมด" }, + { id: "PENDING", name: "รอดำเนินการ" }, + { id: "APPROVE", name: "อนุมัติ" }, + { id: "REJECT", name: "ไม่อนุมัติ" }, + ]); + + // convertStatus function convertStatus(val: string) { const value = val ? val.toUpperCase() : null; switch (value) { @@ -29,5 +36,6 @@ export const useSpecialTimeStore = defineStore("LeaveSpecialTime", () => { return { optionStatus, convertStatus, + optionStatusMain, }; }); diff --git a/src/modules/09_leave/views/04_SpecialTimeMain.vue b/src/modules/09_leave/views/04_SpecialTimeMain.vue index 10b9dc8df..1ea9ec44b 100644 --- a/src/modules/09_leave/views/04_SpecialTimeMain.vue +++ b/src/modules/09_leave/views/04_SpecialTimeMain.vue @@ -10,8 +10,10 @@ import { useSpecialTimeStore } from "@/modules/09_leave/stores/SpecialTimeStore" import { checkPermission } from "@/utils/permissions"; import { usePagination } from "@/composables/usePagination"; -import type { DataDateMonthObject } from "@/modules/09_leave/interface/request/specialTime"; -import type { DataSpecialTime } from "@/modules/09_leave/interface/index/Main"; +import type { + DataSpecialTime, + DataOption, +} from "@/modules/09_leave/interface/index/Main"; import DialogReason from "@/components/Dialogs/PopupReason.vue"; import DialogApprove from "@/modules/09_leave/components/04_SpecialTime/DialogApprove.vue"; @@ -21,23 +23,17 @@ const mixin = useCounterMixin(); const store = useSpecialTimeStore(); const { hideLoader, - monthYear2Thai, messageError, showLoader, success, date2Thai, dialogConfirm, + dateToISO, } = mixin; const { pagination, params, onRequest } = usePagination("", fetchData); const emit = defineEmits(["update:change-page"]); -const toDay = ref(new Date()); -const monthToday = toDay.value.getMonth(); -const yearToday = toDay.value.getFullYear(); - -const month = ref(monthToday + 1); -const year = ref(yearToday); const description = ref(""); /**ตัวแปรที่ใช้ */ @@ -51,16 +47,12 @@ const name = ref(""); const id = ref(""); const dateDialog = ref(""); const dateFixDialog = ref(""); -const dateYear = ref(new Date().getFullYear()); - -/** Function Date */ -const dateMonth = ref({ - month: new Date().getMonth(), - year: new Date().getFullYear(), -}); // ค้นหาในตาราง const filterKeyword = ref(""); +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([ "no", @@ -144,9 +136,10 @@ async function fetchData() { .get(config.API.specialTime(), { params: { ...params.value, - year: year.value, - month: month.value, keyword: filterKeyword.value.trim(), + status: filterStatus.value != "ALL" ? filterStatus.value : null, + startDate: filterDate.value ? dateToISO(filterDate.value[0]) : null, + endDate: filterDate.value ? dateToISO(filterDate.value[1]) : null, }, }) .then(async (res) => { @@ -246,40 +239,43 @@ async function clickSave(reason: string) { }); } -/** - * ดึงข้อมูลตามปี - * @param e ปี - */ -async function updateMonth(e: DataDateMonthObject) { - if (e != null) { - dateYear.value = e.year; - dateYear.value = year.value; - month.value = dateMonth.value.month + 1; - year.value = dateMonth.value.year; - onSearchData(); - } -} - -//แปลงเดือนเป็นไทย -function monthYearThai(val: DataDateMonthObject) { - if (val == null) return ""; - else return monthYear2Thai(val.month, val.year); -} - /** ฟังก์ชั่นค้นหาข้อมูล */ function onSearchData() { pagination.value.page = 1; fetchData(); } +/** + * ฟังก์ชั่นค้นหาข้อมูลของ Option Filter + * @param val คำที่ค้นหา + * @param update Function + * @param typeOp ประเภทของ Select + */ +function filterOption(val: string, update: Function) { + update(() => { + const needle = val.toLowerCase(); + optionStatus.value = store.optionStatusMain.filter( + (v: DataOption) => v.name.toLowerCase().indexOf(needle) > -1 + ); + }); +} + +/** + * แปลงช่วงวันที่ถ้า2ค่าเป็นวันเดียวกันจะโชววันเดียวแต่ถ้าไม่เท่ากันจะแสดงเป็นช่วง + * @param val ช่วงวันที่ + */ +function dateThaiRange(val: [Date, Date]) { + if (val === null) { + return ""; + } else if (date2Thai(val[0], true) === date2Thai(val[1], true)) { + return `${date2Thai(val[0], true)}`; + } else { + return `${date2Thai(val[0], true)} - ${date2Thai(val[1], true)}`; + } +} + /**Hook */ onMounted(async () => { - //อัพเดทเป็นวันปัจจุบันเมื่อเข้าหน้านี้ - const toDay = ref(new Date()); - const monthToday = toDay.value.getMonth(); - const yearToday = toDay.value.getFullYear(); - month.value = monthToday + 1; - year.value = yearToday; await fetchData(); }); @@ -291,25 +287,31 @@ onMounted(async () => {
-
+
- - + + From 8dc473eec0f99d6bbfe5ae7a104e6362124a07a7 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Mon, 11 May 2026 15:54:10 +0700 Subject: [PATCH 12/46] refactor(leave): validate isAct commander --- .../components/05_Leave/DetailLeavePage.vue | 33 +++++++++++++++---- .../05_Leave/Dialog/DialogAddCommander.vue | 11 +++++-- .../09_leave/interface/response/leave.ts | 2 ++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/modules/09_leave/components/05_Leave/DetailLeavePage.vue b/src/modules/09_leave/components/05_Leave/DetailLeavePage.vue index 4f4b2ee46..b74df44e6 100644 --- a/src/modules/09_leave/components/05_Leave/DetailLeavePage.vue +++ b/src/modules/09_leave/components/05_Leave/DetailLeavePage.vue @@ -150,21 +150,41 @@ const rows = ref(); // เช็คสิทธิ์การอนุมัติ const idCheck = computed(() => { if (typeAdd.value == "COMMANDER") { - return rows.value?.commanders.map((items: SeqTypeRow) => items.profileId); + return rows.value?.commanders.map((items: SeqTypeRow) => items.keyId); } else if (typeAdd.value == "APPROVER") { - return rows.value?.approvers.map((items: SeqTypeRow) => items.profileId); + return rows.value?.approvers.map((items: SeqTypeRow) => items.keyId); } }); // เช็คสิทธิ์การเลือกผู้มีอำนาจ const commanderList = computed(() => { - if (typeAdd.value == "COMMANDER") { - return rows.value?.approvers.map((items: SeqTypeRow) => items.profileId); - } else if (typeAdd.value == "APPROVER") { - return rows.value?.commanders.map((items: SeqTypeRow) => items.profileId); + if (typeAdd.value === "COMMANDER") { + return rows.value?.approvers.map((items: SeqTypeRow) => ({ + profileId: items.profileId, + isAct: items.isAct, + })); + } else if (typeAdd.value === "APPROVER") { + return rows.value?.commanders.map((items: SeqTypeRow) => ({ + profileId: items.profileId, + isAct: items.isAct, + })); } + return []; }); +// +const isAct = computed(() => { + if (typeAdd.value === "COMMANDER") { + return rows.value?.commanders && rows.value.commanders.length > 0 + ? rows.value.commanders[0].isAct + : false; + } else if (typeAdd.value === "APPROVER") { + return rows.value?.approvers && rows.value.approvers.length > 0 + ? rows.value.approvers[0].isAct + : false; + } + return false; +}); // เช็คว่าผู้ใช้มีสิทธิ์อนุมัติหรือไม่ const approveCheck = computed(() => { const commanders = rows.value?.commanders; @@ -1272,5 +1292,6 @@ onMounted(async () => { :id-check="idCheck" :keycloak-user-id="keycloakUserId" :commanders-list="commanderList" + :commanders-is-act="isAct" /> 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 c3eac2353..f3c2e682f 100644 --- a/src/modules/09_leave/components/05_Leave/Dialog/DialogAddCommander.vue +++ b/src/modules/09_leave/components/05_Leave/Dialog/DialogAddCommander.vue @@ -30,6 +30,7 @@ const props = defineProps({ fetchDetailLeave: Function, idCheck: Array, commandersList: Array, + commandersIsAct: Boolean, }); const pageId = ref(route.params.id as string); @@ -117,7 +118,7 @@ async function getData() { total.value = data.total; rows.value = data.data; selected.value = data.data.filter((items: any) => { - return props.idCheck?.some((i: any) => i === items.id); + return props.idCheck?.some((i: any) => i === items.key); }); }) .catch((err) => { @@ -153,10 +154,14 @@ function onSubmit() { ] .filter(Boolean) .join(" "), + isAct: isAct.value, + keyId: items.key, })); const hasCommander = selected.value.some((e) => - props.commandersList?.some((i: any) => i === e.id) + props.commandersList?.some( + (i: any) => i.profileId === e.id && i.isAct === isAct.value + ) ); if (hasCommander) { @@ -205,6 +210,7 @@ watch( () => modal.value, () => { if (modal.value) { + isAct.value = props.commandersIsAct ?? false; getSearch(); } } @@ -233,6 +239,7 @@ watch( label="ค้นหา" v-model="keyword" style="width: 300px" + @keydown.enter.prevent="onSearchData()" >