1813 lines
65 KiB
Vue
1813 lines
65 KiB
Vue
<!-- =============================== -->
|
|
<!-- หน้า ผังโครงสร้าง(Tree) ของ โครงสร้างอัตรากำลัง -->
|
|
<!-- =============================== -->
|
|
<template>
|
|
<div class="toptitle text-dark col-12 row items-center">ผังโครงสร้าง</div>
|
|
<div class="text-dark">
|
|
<q-card flat bordered class="col-12 q-mt-sm">
|
|
<q-layout
|
|
view="hHh Lpr lff"
|
|
container
|
|
style="height: 80vh"
|
|
class="shadow-2 rounded-borders page-relative"
|
|
>
|
|
<!--Drawer Person Detail-->
|
|
<q-drawer
|
|
v-model="isDrawer"
|
|
:width="220"
|
|
:breakpoint="400"
|
|
class="bg-grey-1"
|
|
bordered
|
|
>
|
|
<q-btn
|
|
size="13px"
|
|
class="btn-absolute btnShadow"
|
|
color="white"
|
|
dense
|
|
round
|
|
unelevated
|
|
@click="isDrawer = false"
|
|
v-if="isDrawer"
|
|
>
|
|
<q-icon name="chevron_left" size="20px" color="grey-7" />
|
|
</q-btn>
|
|
<q-scroll-area class="fit">
|
|
<div class="row col-12 text-dark q-pt-sm">
|
|
<div class="col-12 column items-center q-py-lg">
|
|
<img
|
|
v-if="
|
|
personDetail == null ||
|
|
personDetail.avatar == '' ||
|
|
personDetail.avatar ==
|
|
'https://cdn.quasar.dev/img/boy-avatar.png'
|
|
"
|
|
src="@/assets/avatar_user.jpg"
|
|
style="width: 90px; height: 90px; border-radius: 50%"
|
|
/>
|
|
<img
|
|
v-else
|
|
:src="personDetail.avatar"
|
|
style="width: 90px; height: 90px; border-radius: 50%"
|
|
/>
|
|
</div>
|
|
<div class="col-12 items-center row col-12 justify-center">
|
|
<div style="font-weight: 600" class="q-mr-xs">
|
|
{{ personDetail ? personDetail.name : "" }}
|
|
</div>
|
|
<q-btn dense flat size="10px">
|
|
<q-icon
|
|
name="mdi-open-in-new"
|
|
size="15px"
|
|
color="grey-6"
|
|
@click="goToUserRegistry()"
|
|
/>
|
|
<q-tooltip>ทะเบียนประวัติ</q-tooltip>
|
|
</q-btn>
|
|
</div>
|
|
<div class="q-pl-lg q-pt-sm q-gutter-xs textSub">
|
|
<div class="text-weight-medium q-pt-md row items-center">
|
|
<q-icon size="10px" color="grey-4" name="mdi-circle" />
|
|
<div class="q-pl-sm">ตำแหน่งเลขที่</div>
|
|
</div>
|
|
<div class="text-grey-7 q-pl-lg">
|
|
{{ personDetail ? personDetail.positionNum : "" }}
|
|
</div>
|
|
|
|
<!-- <div class="text-weight-medium q-pt-md row items-center">
|
|
<q-icon size="10px" color="grey-4" name="mdi-circle" />
|
|
<div class="q-pl-sm">ตำแหน่งในการบริหารงาน</div>
|
|
</div>
|
|
<div class="text-grey-7 q-pl-lg">
|
|
{{ personDetail ? personDetail.executivePosition : "" }}
|
|
</div> -->
|
|
|
|
<div class="text-weight-medium q-pt-md row items-center">
|
|
<q-icon size="10px" color="grey-4" name="mdi-circle" />
|
|
<div class="q-pl-sm">ประเภทตำแหน่ง</div>
|
|
</div>
|
|
<div class="text-grey-7 q-pl-lg">
|
|
{{ personDetail ? personDetail.positionType : "" }}
|
|
</div>
|
|
|
|
<div class="text-weight-medium q-pt-md row items-center">
|
|
<q-icon size="10px" color="grey-4" name="mdi-circle" />
|
|
<div class="q-pl-sm">ระดับตำแหน่ง</div>
|
|
</div>
|
|
<div class="text-grey-7 q-pl-lg">
|
|
{{ personDetail ? personDetail.positionLevel : "" }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</q-scroll-area>
|
|
</q-drawer>
|
|
|
|
<!--Edit Button Set and Search Tree input and Show Free positionNum-->
|
|
<q-page-container class="col-12 row">
|
|
<q-page padding style="padding-top: 70px">
|
|
<!-- Button Set -->
|
|
<q-page-sticky
|
|
expand
|
|
position="top"
|
|
class="bg-white pageSK q-pt-sm"
|
|
>
|
|
<div
|
|
class="col-12 q-px-md row items-center q-py-sm q-col-gutter-xs"
|
|
>
|
|
<div class="row">
|
|
<buttonsSet
|
|
v-model:editvisible="isShowEditTree"
|
|
:deleteDraft="deleteDraft"
|
|
:publishDraft="publishDraft"
|
|
:refreshData="resetTree"
|
|
:publicData="version === 'published'"
|
|
/><q-btn
|
|
color="info"
|
|
flat
|
|
dense
|
|
round
|
|
size="14px"
|
|
icon="mdi-history"
|
|
@click="clickHistory"
|
|
><q-tooltip>ประวัติการเผยแพร่</q-tooltip>
|
|
</q-btn>
|
|
</div>
|
|
<q-space />
|
|
<q-select
|
|
dense
|
|
outlined
|
|
v-model="selectedFile"
|
|
:options="fileList"
|
|
class="col-xs-12 col-sm-4 col-md-3"
|
|
map-options
|
|
emit-value
|
|
v-if="!isShowEditTree"
|
|
/>
|
|
<q-input
|
|
outlined
|
|
dense
|
|
style="max-width: 200px"
|
|
ref="treeFilterRef"
|
|
v-model="treeFilter"
|
|
placeholder="ค้นหา"
|
|
debounce="300"
|
|
>
|
|
<template v-slot:append>
|
|
<q-icon v-if="treeFilter == ''" name="search" />
|
|
<q-icon
|
|
v-if="treeFilter !== ''"
|
|
name="clear"
|
|
class="cursor-pointer"
|
|
@click="resetFilter"
|
|
/>
|
|
</template>
|
|
</q-input>
|
|
</div>
|
|
</q-page-sticky>
|
|
|
|
<!-- Tree View-->
|
|
<div class="q-gutter-sm">
|
|
<q-tree
|
|
v-show="!isShowEditTree"
|
|
no-transition
|
|
ref="qtreeView"
|
|
:nodes="dataTree"
|
|
:no-results-label="treeSearchNotFound"
|
|
:no-nodes-label="noTreeData"
|
|
node-key="keyId"
|
|
:filter="treeFilter"
|
|
:filter-method="treeFilterMethod"
|
|
v-model:expanded="expandedNodeView"
|
|
>
|
|
<!--organization บรรทัดแสดงชื่อหน่วยงาน -->
|
|
<template v-slot:header-organization="prop">
|
|
<div class="row items-center q-px-xs q-pt-xs q-gutter-sm">
|
|
<!--แสดงชื่อแผนก พิมพ์ตัวหนา คลิกแล้วกาง/หุบ Tree-->
|
|
<div>
|
|
<div class="text-weight-medium">
|
|
{{ prop.node.organizationName }}
|
|
</div>
|
|
<div class="text-weight-light">
|
|
{{
|
|
prop.node.organizationParentId == null
|
|
? null
|
|
: prop.node.governmentCode
|
|
}}
|
|
{{
|
|
prop.node.organizationParentId == null
|
|
? null
|
|
: prop.node.agency
|
|
}}
|
|
{{
|
|
prop.node.organizationParentId == null
|
|
? null
|
|
: prop.node.government
|
|
}}
|
|
{{
|
|
prop.node.organizationParentId == null
|
|
? null
|
|
: prop.node.department
|
|
}}
|
|
{{
|
|
prop.node.organizationParentId == null
|
|
? null
|
|
: prop.node.pile
|
|
}}
|
|
{{
|
|
prop.node.organizationParentId == null
|
|
? null
|
|
: prop.node.organizationShortName
|
|
}}
|
|
</div>
|
|
</div>
|
|
<!--แสดง Total Count PositionNum-->
|
|
<q-badge
|
|
rounded
|
|
color="grey-2"
|
|
text-color="dark"
|
|
:label="prop.node.totalPositionCount"
|
|
/>
|
|
<q-badge
|
|
v-if="prop.node.totalPositionVacant > 0"
|
|
rounded
|
|
color="red"
|
|
outline
|
|
:label="prop.node.totalPositionVacant"
|
|
/>
|
|
</div>
|
|
</template>
|
|
<!--person บรรทัดแถวแสดงชื่อพนักงานอย่างเดียว-->
|
|
<template v-slot:header-person="prop">
|
|
<div
|
|
class="row items-center text-dark col-12 q-py-xs q-pl-sm rounded-borders pointer"
|
|
style="width: 100%"
|
|
>
|
|
<img
|
|
v-if="
|
|
prop.node.avatar == '' ||
|
|
prop.node.avatar ==
|
|
'https://cdn.quasar.dev/img/boy-avatar.png'
|
|
"
|
|
src="@/assets/avatar_user.jpg"
|
|
class="col-xs-1 col-sm-2"
|
|
style="width: 28px; height: 28px; border-radius: 50%"
|
|
/>
|
|
<img
|
|
v-else
|
|
:src="prop.node.avatar"
|
|
class="col-xs-1 col-sm-2"
|
|
style="width: 28px; height: 28px; border-radius: 50%"
|
|
/>
|
|
<div class="row" @click="seeUserDetail(prop.node)">
|
|
<!--=====ตำแหน่งว่าง สีแดง=====-->
|
|
<div
|
|
v-if="
|
|
prop.node.name == `ว่าง` ||
|
|
prop.node.name == `N/A` ||
|
|
prop.node.name == null
|
|
"
|
|
class="q-px-sm text-weight-medium text-red"
|
|
>
|
|
ว่าง
|
|
</div>
|
|
<!--=====หัวหน้า สีเขียว=====-->
|
|
<div v-else-if="prop.node.positionLeaderFlag">
|
|
<div class="q-px-sm text-weight-medium text-primary">
|
|
{{ prop.node.name }}
|
|
</div>
|
|
</div>
|
|
<!--=====ลูกน้อง สีปกติ=====-->
|
|
<div v-else>
|
|
<div class="q-px-sm text-weight-medium">
|
|
{{ prop.node.name }}
|
|
</div>
|
|
</div>
|
|
<!--ต่อท้ายชื่อคน แสดงสีปกติ-->
|
|
<div class="q-pr-sm">
|
|
{{ prop.node.positionName }}
|
|
</div>
|
|
<div
|
|
class="q-pr-sm"
|
|
v-if="
|
|
prop.node.positionType != null &&
|
|
prop.node.positionType != ''
|
|
"
|
|
>
|
|
ประเภท{{ `${prop.node.positionType}` }}
|
|
</div>
|
|
<div
|
|
class="q-pr-sm"
|
|
v-if="
|
|
prop.node.positionLevel != null &&
|
|
prop.node.positionLevel != ''
|
|
"
|
|
>
|
|
ระดับ{{ `${prop.node.positionLevel}` }}
|
|
</div>
|
|
<div
|
|
class="q-pr-sm"
|
|
v-if="
|
|
prop.node.executivePosition != null &&
|
|
prop.node.executivePosition != ''
|
|
"
|
|
>
|
|
{{ `(${prop.node.executivePosition})` }}
|
|
</div>
|
|
<div class="q-pr-sm">
|
|
{{ prop.node.positionNum }}
|
|
</div>
|
|
</div>
|
|
<q-icon
|
|
v-if="prop.node.positionLeaderFlag"
|
|
class="q-mr-sm"
|
|
size="15px"
|
|
color="primary"
|
|
name="mdi-bookmark"
|
|
/>
|
|
<!-- <div
|
|
class="text-white"
|
|
style="font-size: 1px; display: none"
|
|
>
|
|
{{ prop.node.positionLevel }}
|
|
</div> -->
|
|
</div>
|
|
</template>
|
|
</q-tree>
|
|
</div>
|
|
<!--Tree Edit-->
|
|
<div class="q-gutter-sm">
|
|
<!-- must use v-if to be able to use lazyLoad for second time-->
|
|
<q-tree
|
|
v-if="isShowEditTree"
|
|
no-transition
|
|
ref="qtreeEdit"
|
|
:nodes="dataTreeDraft"
|
|
:no-results-label="treeSearchNotFound"
|
|
:no-nodes-label="noTreeData"
|
|
node-key="keyId"
|
|
:filter="treeFilter"
|
|
:filter-method="treeFilterMethod"
|
|
@lazy-load="onLazyLoad"
|
|
v-model:expanded="expandedNodeEdit"
|
|
dense
|
|
>
|
|
<!--organization บรรทัดแสดงชื่อหน่วยงาน & ปุ่ม + -->
|
|
<template v-slot:header-organization="prop">
|
|
<div class="row items-center q-px-xs q-pt-xs q-gutter-sm">
|
|
<!--แสดงชื่อแผนก พิมพ์ตัวหนา คลิกแล้วกาง/หุบ Tree-->
|
|
<div>
|
|
<div class="text-weight-medium">
|
|
{{ prop.node.organizationName }}
|
|
</div>
|
|
<div class="text-weight-light">
|
|
{{
|
|
prop.node.organizationParentId == null
|
|
? null
|
|
: prop.node.governmentCode
|
|
}}
|
|
{{
|
|
prop.node.organizationParentId == null
|
|
? null
|
|
: prop.node.agency
|
|
}}
|
|
{{
|
|
prop.node.organizationParentId == null
|
|
? null
|
|
: prop.node.government
|
|
}}
|
|
{{
|
|
prop.node.organizationParentId == null
|
|
? null
|
|
: prop.node.department
|
|
}}
|
|
{{
|
|
prop.node.organizationParentId == null
|
|
? null
|
|
: prop.node.pile
|
|
}}
|
|
{{
|
|
prop.node.organizationParentId == null
|
|
? null
|
|
: prop.node.organizationShortName
|
|
}}
|
|
</div>
|
|
</div>
|
|
<!--แสดง Total Count PositionNum-->
|
|
<q-badge
|
|
rounded
|
|
color="grey-2"
|
|
text-color="dark"
|
|
:label="prop.node.totalPositionCount"
|
|
/>
|
|
<q-badge
|
|
v-if="prop.node.totalPositionVacant > 0"
|
|
rounded
|
|
color="red"
|
|
outline
|
|
:label="prop.node.totalPositionVacant"
|
|
/>
|
|
<q-btn
|
|
flat
|
|
round
|
|
color="green"
|
|
@click.stop="
|
|
(popupAddOrganization = true),
|
|
(modalHeaderName = prop.node.organizationName),
|
|
(rowClickTree = prop.node),
|
|
(modalHeaderPosition =
|
|
prop.node.keyId.search('-') > 0 ? true : false)
|
|
"
|
|
size="10px"
|
|
icon="mdi-plus"
|
|
>
|
|
<q-tooltip>เพิ่มโครงสร้าง</q-tooltip>
|
|
</q-btn>
|
|
<!--
|
|
v-if="
|
|
prop.node.totalPositionCount ==
|
|
prop.node.totalPositionVacant
|
|
"
|
|
-->
|
|
<q-btn
|
|
v-if="prop.node.organizationId != orgRootIdDraft"
|
|
flat
|
|
round
|
|
color="edit"
|
|
@click.stop="
|
|
(popupEditSelectedOrganization = true),
|
|
(modalHeaderName = prop.node.organizationName),
|
|
(rowClickTree = prop.node),
|
|
(modalHeaderPosition =
|
|
prop.node.keyId.search('-') > 0 ? true : false)
|
|
"
|
|
size="10px"
|
|
icon="mdi-pencil"
|
|
>
|
|
<q-tooltip>แก้ไขหน่วยงาน</q-tooltip>
|
|
</q-btn>
|
|
<q-btn
|
|
v-if="
|
|
prop.node.totalPositionCount ==
|
|
prop.node.totalPositionVacant &&
|
|
prop.node.organizationId != orgRootIdDraft
|
|
"
|
|
flat
|
|
round
|
|
color="red"
|
|
size="10px"
|
|
class="q-mr-sm"
|
|
icon="mdi-trash-can-outline"
|
|
@click.stop="deleteOrganization(prop.node)"
|
|
>
|
|
<q-tooltip>ลบหน่วยงาน</q-tooltip>
|
|
</q-btn>
|
|
<q-space />
|
|
</div>
|
|
</template>
|
|
<!--person บรรทัดแถวแสดงชื่อพนักงานอย่างเดียว-->
|
|
<template v-slot:header-person="prop">
|
|
<div class="row items-center q-px-xs q-pt-xs q-gutter-sm">
|
|
<div
|
|
rounded
|
|
:style="
|
|
!prop.node.isActive ? 'filter: grayscale(60%);' : ''
|
|
"
|
|
>
|
|
<img
|
|
v-if="
|
|
prop.node.avatar == '' ||
|
|
prop.node.avatar ==
|
|
'https://cdn.quasar.dev/img/boy-avatar.png'
|
|
"
|
|
src="@/assets/avatar_user.jpg"
|
|
class="col-xs-1 col-sm-2"
|
|
style="width: 28px; height: 28px; border-radius: 50%"
|
|
/>
|
|
<img
|
|
v-else
|
|
:src="prop.node.avatar"
|
|
class="col-xs-1 col-sm-2"
|
|
style="width: 28px; height: 28px; border-radius: 50%"
|
|
/>
|
|
</div>
|
|
|
|
<div
|
|
rounded
|
|
:class="
|
|
!prop.node.isActive ? 'text-grey-6' : 'text-black'
|
|
"
|
|
>
|
|
<!--=====ตำแหน่งว่าง สีแดง=====-->
|
|
<div class="row">
|
|
<div
|
|
v-if="
|
|
prop.node.name == `ว่าง` ||
|
|
prop.node.name == `N/A` ||
|
|
prop.node.name == null
|
|
"
|
|
class="q-px-sm text-weight-medium"
|
|
:class="
|
|
!prop.node.isActive ? 'text-grey-6' : 'text-red'
|
|
"
|
|
>
|
|
ว่าง
|
|
</div>
|
|
<!--=====หัวหน้า สีเขียว=====-->
|
|
<div v-else-if="prop.node.positionLeaderFlag">
|
|
<div class="q-px-sm text-weight-medium text-primary">
|
|
{{ prop.node.name }}
|
|
</div>
|
|
</div>
|
|
<!--=====ลูกน้อง สีปกติ=====-->
|
|
<div v-else>
|
|
<div class="q-px-sm text-weight-medium">
|
|
{{ prop.node.name }}
|
|
</div>
|
|
</div>
|
|
<!--ต่อท้ายชื่อคน แสดงสีปกติ-->
|
|
<div class="q-pr-sm">
|
|
{{ prop.node.positionName }}
|
|
</div>
|
|
<div
|
|
class="q-pr-sm"
|
|
v-if="
|
|
prop.node.positionType != null &&
|
|
prop.node.positionType != ''
|
|
"
|
|
>
|
|
ประเภท{{ prop.node.positionType }}
|
|
</div>
|
|
<div
|
|
class="q-pr-sm"
|
|
v-if="
|
|
prop.node.positionLevel != null &&
|
|
prop.node.positionLevel != ''
|
|
"
|
|
>
|
|
ระดับ{{ prop.node.positionLevel }}
|
|
</div>
|
|
<div
|
|
class="q-pr-sm"
|
|
v-if="
|
|
prop.node.executivePosition != null &&
|
|
prop.node.executivePosition != ''
|
|
"
|
|
>
|
|
{{ `(${prop.node.executivePosition})` }}
|
|
</div>
|
|
<div class="q-pr-sm">
|
|
{{ prop.node.positionNum }}
|
|
</div>
|
|
</div>
|
|
<div class="q-pl-sm text-weight-light">
|
|
{{ prop.node.positionSideName }}
|
|
<!-- {{ prop.node.executivePosition }} -->
|
|
{{ prop.node.executivePositionSide }}
|
|
</div>
|
|
</div>
|
|
<q-icon
|
|
v-if="prop.node.positionLeaderFlag"
|
|
class="q-mr-sm"
|
|
size="15px"
|
|
color="primary"
|
|
name="mdi-bookmark"
|
|
></q-icon
|
|
><q-btn
|
|
v-if="
|
|
prop.node.name == `ว่าง` ||
|
|
prop.node.name == `N/A` ||
|
|
prop.node.name == null
|
|
"
|
|
flat
|
|
round
|
|
color="green"
|
|
@click.stop="
|
|
(popupEditSelectedPosition = true),
|
|
(modalHeaderName = prop.node.positionName),
|
|
(rowClickTree = prop.node),
|
|
(modalHeaderPosition =
|
|
prop.node.keyId.search('-') > 0 ? true : false)
|
|
"
|
|
size="10px"
|
|
icon="mdi-pencil-outline"
|
|
>
|
|
<q-tooltip>แก้ไขตำแหน่ง</q-tooltip>
|
|
</q-btn>
|
|
<q-btn
|
|
v-if="
|
|
prop.node.name == `ว่าง` ||
|
|
prop.node.name == `N/A` ||
|
|
prop.node.name == null
|
|
"
|
|
flat
|
|
round
|
|
color="red"
|
|
size="10px"
|
|
class="q-mr-sm"
|
|
icon="mdi-trash-can-outline"
|
|
@click.stop="deletePosition(prop.node)"
|
|
>
|
|
<q-tooltip>ลบตำแหน่ง</q-tooltip>
|
|
</q-btn>
|
|
<q-space />
|
|
<!-- <div
|
|
class="text-white"
|
|
style="font-size: 1px; display: none"
|
|
>
|
|
{{ prop.node.positionLevel }}
|
|
</div> -->
|
|
</div>
|
|
</template>
|
|
</q-tree>
|
|
</div>
|
|
</q-page>
|
|
</q-page-container>
|
|
<!-- popup Add Organizations & Positions -->
|
|
<q-dialog v-model="popupAddOrganization" persistent>
|
|
<q-card class="text-dark" style="min-width: 950px">
|
|
<q-card-section class="row items-center q-py-sm">
|
|
<div class="text-bold">เพิ่มโครงสร้างอัตรากำลังภายใต้</div>
|
|
<strong class="text-primary q-pl-sm">{{
|
|
modalHeaderName
|
|
}}</strong>
|
|
<q-space />
|
|
<q-btn
|
|
icon="close"
|
|
unelevated
|
|
round
|
|
dense
|
|
style="color: #ff8080; background-color: #ffdede"
|
|
size="12px"
|
|
v-close-popup
|
|
/>
|
|
</q-card-section>
|
|
|
|
<q-separator />
|
|
|
|
<q-card-section
|
|
style="min-height: 60vh; max-height: 70vh"
|
|
class="scroll"
|
|
>
|
|
<organizationComponent
|
|
v-model:organizprops="organizationData"
|
|
v-model:formprops="organizationForm"
|
|
/>
|
|
<br />
|
|
<positionsComponent
|
|
v-model:positions="positionData"
|
|
v-model:formprops="positionForm"
|
|
:is-add-new="true"
|
|
v-if="modalHeaderPosition"
|
|
/>
|
|
</q-card-section>
|
|
|
|
<q-separator />
|
|
|
|
<q-card-actions align="right" class="text-primary q-py-sm">
|
|
<!-- Save for Add Organizations & Positions -->
|
|
<q-btn
|
|
flat
|
|
round
|
|
dense
|
|
:color="'public'"
|
|
@click="addStructure(rowClickTree)"
|
|
icon="mdi-content-save-outline"
|
|
>
|
|
<q-tooltip>บันทึก</q-tooltip>
|
|
</q-btn>
|
|
</q-card-actions>
|
|
</q-card>
|
|
</q-dialog>
|
|
<!-- popup Edit Selected Position -->
|
|
<q-dialog v-model="popupEditSelectedPosition" persistent>
|
|
<q-card class="text-dark" style="min-width: 70vw">
|
|
<q-card-section class="row items-center q-py-sm">
|
|
<div class="text-bold">แก้ไขตำแหน่ง</div>
|
|
<strong class="text-primary q-pl-sm">{{
|
|
modalHeaderName
|
|
}}</strong>
|
|
<q-space />
|
|
<q-btn
|
|
icon="close"
|
|
unelevated
|
|
round
|
|
dense
|
|
style="color: #ff8080; background-color: #ffdede"
|
|
size="12px"
|
|
v-close-popup
|
|
/>
|
|
</q-card-section>
|
|
<q-separator />
|
|
<q-card-section>
|
|
<positionsComponent
|
|
v-model:positions="positionData"
|
|
v-model:formprops="positionForm"
|
|
:is-add-new="false"
|
|
:editObj="rowClickTree"
|
|
/>
|
|
</q-card-section>
|
|
<q-separator />
|
|
<q-card-actions align="right" class="text-primary q-py-sm">
|
|
<!-- save Edit Selected Position -->
|
|
<q-btn
|
|
flat
|
|
dense
|
|
round
|
|
:color="'public'"
|
|
@click="editPositionStructure(rowClickTree)"
|
|
icon="mdi-content-save-outline"
|
|
>
|
|
<q-tooltip>บันทึก</q-tooltip>
|
|
</q-btn>
|
|
</q-card-actions>
|
|
</q-card>
|
|
</q-dialog>
|
|
<!-- popup Edit Selected Organization -->
|
|
<q-dialog v-model="popupEditSelectedOrganization" persistent>
|
|
<q-card class="text-dark" style="min-width: 70vw">
|
|
<q-card-section class="row items-center q-py-sm">
|
|
<div class="text-bold">แก้ไขหน่วยงาน</div>
|
|
<strong class="text-primary q-pl-sm">{{
|
|
modalHeaderName
|
|
}}</strong>
|
|
<q-space />
|
|
<q-btn
|
|
icon="close"
|
|
unelevated
|
|
round
|
|
dense
|
|
style="color: #ff8080; background-color: #ffdede"
|
|
size="12px"
|
|
v-close-popup
|
|
/>
|
|
</q-card-section>
|
|
<q-separator />
|
|
<q-card-section>
|
|
<organizationEditComponent
|
|
v-model:organizprops="organizationDataEdit"
|
|
v-model:formprops="organizationForm"
|
|
:org="rowClickTree"
|
|
/>
|
|
</q-card-section>
|
|
<q-separator />
|
|
<q-card-actions align="right" class="text-primary q-py-sm">
|
|
<!-- save Edit Selected Organization -->
|
|
<q-btn
|
|
flat
|
|
dense
|
|
round
|
|
:color="'public'"
|
|
@click="editOrgStructure(rowClickTree)"
|
|
icon="mdi-content-save-outline"
|
|
>
|
|
<q-tooltip>บันทึก</q-tooltip>
|
|
</q-btn>
|
|
</q-card-actions>
|
|
</q-card>
|
|
</q-dialog>
|
|
</q-layout>
|
|
</q-card>
|
|
</div>
|
|
|
|
<HistoryTable
|
|
:rows="rowsHistory"
|
|
:columns="columnsHistory"
|
|
:filter="filterHistory"
|
|
:visible-columns="visibleColumnsHistory"
|
|
:boss="true"
|
|
v-model:modal="modalHistory"
|
|
v-model:inputfilter="filterHistory"
|
|
v-model:inputvisible="visibleColumnsHistory"
|
|
v-model:tittle="tittleHistory"
|
|
>
|
|
<template #columns="props">
|
|
<q-tr :props="props">
|
|
<q-td auto-width>
|
|
<q-icon
|
|
class="q-mr-sm"
|
|
size="15px"
|
|
color="primary"
|
|
name="mdi-bookmark"
|
|
v-if="props.row.isDirector"
|
|
></q-icon>
|
|
</q-td>
|
|
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
|
<div v-if="col.name == 'isActive'" class="">
|
|
<q-icon
|
|
v-if="col.value == false"
|
|
name="mdi-close"
|
|
color="red"
|
|
class="text-h5"
|
|
/>
|
|
<q-icon v-else name="mdi-check" color="positive" class="text-h5" />
|
|
</div>
|
|
<div v-else class="">
|
|
{{ col.value }}
|
|
</div>
|
|
</q-td>
|
|
</q-tr>
|
|
</template>
|
|
</HistoryTable>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
// import tree_data from "@/assets/tree.json";
|
|
import { stringLiteral, typeParameterDeclaration } from "@babel/types";
|
|
import { ref, defineAsyncComponent, watch, onMounted } from "vue";
|
|
import { useQuasar, QForm } from "quasar";
|
|
import { useRouter } from "vue-router";
|
|
|
|
import http from "@/plugins/http";
|
|
import config from "@/app.config";
|
|
import { useCounterMixin } from "@/stores/mixin";
|
|
import type { OrganizaOption } from "../interface/index/Main";
|
|
|
|
// import manageApiErrorMsg from "@/global/user_response_msg";
|
|
import HistoryTable from "@/components/TableHistory.vue";
|
|
import type { QTableProps } from "quasar";
|
|
import type {
|
|
RequestItemsObject,
|
|
RequestItemsPublishHistoryObject,
|
|
Columns,
|
|
} from "@/modules/02_organizational/interface/request/Mapping";
|
|
const positionsComponent = defineAsyncComponent(
|
|
() =>
|
|
import("@/modules/02_organizational/components/Tree/MappingPositions.vue")
|
|
); //ชุด Dropdown ตำแหน่ง
|
|
const organizationComponent = defineAsyncComponent(
|
|
() =>
|
|
import("@/modules/02_organizational/components/Tree/OrganizationDialog.vue")
|
|
); //ชุด Dropdown หน่วยงาน for Add
|
|
const organizationEditComponent = defineAsyncComponent(
|
|
() =>
|
|
import(
|
|
"@/modules/02_organizational/components/Tree/OrganizationDialogAddEdit.vue"
|
|
)
|
|
); //ชุด Dropdown หน่วยงาน for Edit ครั้งละ 1 หน่วยงาน
|
|
|
|
const buttonsSet = defineAsyncComponent(
|
|
() => import("@/modules/02_organizational/components/Tree/TreeButtonsSet.vue")
|
|
); //ชุด ปุ่มกด copy from TableView but delete Table
|
|
|
|
// import CustomComponent from "@/components/CustomDialog.vue";
|
|
|
|
const rowsHistory = ref<any[]>([]); //select data history
|
|
const rawHistory = ref<any[]>([]); //raw data history
|
|
const tittleHistory = ref<string>("ประวัติแก้ไขผังโครงสร้าง"); //
|
|
const filterHistory = ref<string>(""); //search data table history
|
|
const modalHistory = ref<boolean>(false); //modal ประวัติการแก้ไขข้อมูล
|
|
|
|
//Global Variable
|
|
|
|
const mixin = useCounterMixin();
|
|
|
|
const { success, messageError, dialogMessage, showLoader, hideLoader } = mixin;
|
|
|
|
//Notification Component Variable
|
|
const $q = useQuasar(); // show dialog
|
|
|
|
//Drawer Person Detail Variable
|
|
const router = useRouter();
|
|
const isDrawer = ref<boolean>(false);
|
|
const isChevronR = ref<boolean>(false); //don't show Drawer btn when first load page
|
|
const personDetail = ref<any>();
|
|
|
|
//Pop-Up Add/Edit Organization Variable
|
|
const popupAddOrganization = ref<boolean>(false); //แสดง pop-up เพิ่ม mapping โครงสร้าง
|
|
const popupEditSelectedOrganization = ref<boolean>(false); //แสดง pop-up Edit หน่วยงานที่เลือก
|
|
const popupEditSelectedPosition = ref<boolean>(false); //แสดง pop-up Edit ตำแหน่งที่เลือก
|
|
const modalHeaderName = ref<string>("กรุงเทพมหานคร/สำนักงาน ก.ก."); //show name of click node on modal
|
|
const modalHeaderPosition = ref<boolean>(true);
|
|
|
|
//ButtonSet Variable
|
|
const version = ref<string>("published"); // คำอื่นจะเปิดปุ่มให้กดได้ :publicData="version === 'published'" (True = Disable Buttons) -->
|
|
const isShowEditTree = ref<boolean>(false); //ปุ่ม edit บน buttonSet //true=draft load draft first
|
|
|
|
//Tree Variable
|
|
const expandedNodeView = ref<Array<string>>([]);
|
|
const expandedNodeEdit = ref<Array<string>>([]);
|
|
const treeFilter = ref<string>("");
|
|
const treeFilterRef = ref<any>(null);
|
|
const treeSearchNotFound = ref<string>("ไม่พบข้อมูลที่ค้นหา");
|
|
const noTreeData = ref<string>("ไม่พบข้อมูลผังโครงสร้าง");
|
|
const organizationForm = ref<QForm | null>(null);
|
|
const positionForm = ref<QForm | null>(null);
|
|
const qtreeView = ref<any>(); //q-tree ref for View
|
|
const qtreeEdit = ref<any>(); //q-tree ref for Edit
|
|
const positionData = ref<Array<any>>([]); //๋Array เก็บ positionSet from positionsComponent
|
|
const organizationData = ref<OrganizaOption[]>([]);
|
|
const organizationDataEdit = ref<OrganizaOption>();
|
|
const orgRootIdDraft = ref<string>(""); // Draft Root Node for not show edit&delete button
|
|
const rowClickTree = ref<Array<Object>>([]); //keep click node and all of it's children
|
|
const dataTree = ref<Array<any>>([]);
|
|
// const dataTree = ref<Array<any>>(jsonDataTree);
|
|
const dataTreeDraft = ref<Array<any>>([]);
|
|
|
|
//deledte Organization & Position Variable function
|
|
const delStructureId = ref<string>("");
|
|
const delStructureKey = ref<string>("");
|
|
|
|
// first load page
|
|
const rootNodeKey = ref<string>("");
|
|
|
|
const fileList = ref<any[]>([]);
|
|
const selectedFile = ref<string>("");
|
|
|
|
const visibleColumnsHistory = ref<String[]>(["detail", "editUser", "editDate"]);
|
|
const columnsHistory = ref<QTableProps["columns"]>([
|
|
{
|
|
name: "detail",
|
|
align: "left",
|
|
label: "รายละเอียด",
|
|
sortable: true,
|
|
field: "detail",
|
|
headerStyle: "font-size: 14px",
|
|
style: "font-size: 14px",
|
|
sort: (a: string, b: string) =>
|
|
a.localeCompare(b, undefined, {
|
|
numeric: true,
|
|
sensitivity: "base",
|
|
}),
|
|
},
|
|
{
|
|
name: "editUser",
|
|
align: "left",
|
|
label: "ผู้ดำเนินการ",
|
|
sortable: true,
|
|
field: "editUser",
|
|
headerStyle: "font-size: 14px",
|
|
style: "font-size: 14px",
|
|
sort: (a: string, b: string) =>
|
|
a.localeCompare(b, undefined, {
|
|
numeric: true,
|
|
sensitivity: "base",
|
|
}),
|
|
},
|
|
{
|
|
name: "editDate",
|
|
align: "left",
|
|
label: "วันที่แก้ไข",
|
|
sortable: true,
|
|
field: "editDate",
|
|
headerStyle: "font-size: 14px",
|
|
style: "font-size: 14px",
|
|
sort: (a: string, b: string) =>
|
|
a.localeCompare(b, undefined, {
|
|
numeric: true,
|
|
sensitivity: "base",
|
|
}),
|
|
},
|
|
]);
|
|
|
|
watch(isShowEditTree, (count, prevCount) => {
|
|
if (isShowEditTree.value) {
|
|
isDrawer.value = false;
|
|
}
|
|
}); // close drawer when enter edit mode
|
|
|
|
watch(selectedFile, async (value, oldValue) => {
|
|
await loadJsonTree(value);
|
|
});
|
|
|
|
onMounted(async () => {
|
|
await fetchTreeRoot(true); //fetch Root Edit Tree level 1
|
|
expandedNodeView.value = [`1`];
|
|
|
|
await loadPublishScreen();
|
|
|
|
await isTreeHasDraft();
|
|
});
|
|
|
|
const loadTreeData = async () => {
|
|
//for test load file on server
|
|
await http
|
|
.get(
|
|
// "https://s3cluster.frappet.com/bma-public-test/organization/strueture/tree.json"
|
|
// "https://s3cluster.frappet.com/bma-public-test/organization/strueture/1-2-สำนักงานคณะกรรมการข้าราชการกรุงเทพมหานคร.json"
|
|
// `https://s3cluster.frappet.com/bma-public-test/organization/strueture/${node.organizationId}-${node.organizationName}.json`
|
|
"https://s3cluster.frappet.com/bma-public-test/organization/strueture/61a11705-8346-4336-8289-49f72ed9463f-%E0%B8%AA%E0%B8%B3%E0%B8%99%E0%B8%B1%E0%B8%81%E0%B8%87%E0%B8%B2%E0%B8%99%E0%B8%84%E0%B8%93%E0%B8%B0%E0%B8%81%E0%B8%A3%E0%B8%A3%E0%B8%A1%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%82%E0%B9%89%E0%B8%B2%E0%B8%A3%E0%B8%B2%E0%B8%8A%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%81%E0%B8%A3%E0%B8%B8%E0%B8%87%E0%B9%80%E0%B8%97%E0%B8%9E%E0%B8%A1%E0%B8%AB%E0%B8%B2%E0%B8%99%E0%B8%84%E0%B8%A3.json"
|
|
)
|
|
.then((res) => {
|
|
dataTree.value = res.data.result;
|
|
})
|
|
.catch((e) => {
|
|
manageApiErrorMsg(e);
|
|
});
|
|
};
|
|
|
|
const loadViewTree = async () => {
|
|
await fetchTreeRoot(false); //fetch root view tree level 1
|
|
dataTree.value[0].lazy = false; //must set lazy to false
|
|
await fetchChildrenByParentId(dataTree.value[0]); // fetch children view tree level 2
|
|
dataTree.value[0].children.forEach((element: any) => {
|
|
//fill all children of all level 2 nodes
|
|
loadFileServer(element);
|
|
});
|
|
};
|
|
|
|
const loadPublishScreen = async () => {
|
|
await fetchPublishFile();
|
|
expandedNodeView.value = [`1`];
|
|
setTimeout(async () => {
|
|
await fetchTreeRoot(false); //fetch root view tree level 1
|
|
dataTree.value[0].lazy = false; //must set lazy to false
|
|
await loadJsonTree(selectedFile.value);
|
|
}, 600);
|
|
};
|
|
|
|
const loadJsonTree = async (fileName: string) => {
|
|
await http
|
|
.get(`${config.s3ClusterUrl}${fileName}`)
|
|
.then((res) => {
|
|
dataTree.value[0].lazy = false; //must set lazy to false
|
|
dataTree.value[0].children = res.data;
|
|
})
|
|
.catch((e) => {
|
|
manageApiErrorMsg(e);
|
|
})
|
|
.finally(() => {
|
|
// hideLoader();
|
|
});
|
|
};
|
|
|
|
const loadFileServer = async (node: any) => {
|
|
// test data = "https://s3cluster.frappet.com/bma-public-test/organization/strueture/tree.json"
|
|
// request = `https://s3cluster.frappet.com/bma-public-test/organization/strueture/${node.organizationId}-${node.organizationName}.json`;
|
|
node.lazy = false; // must set lazy to false
|
|
await http
|
|
.get(
|
|
`${config.s3ClusterUrl}${node.organizationId}-${node.organizationName}.json`
|
|
)
|
|
.then((res) => {
|
|
node.children = res.data;
|
|
})
|
|
.catch((e) => {
|
|
manageApiErrorMsg(e);
|
|
})
|
|
.finally(() => {
|
|
// hideLoader();
|
|
});
|
|
};
|
|
|
|
const isTreeHasDraft = async () => {
|
|
// showLoader();
|
|
let orgHasDraft = false;
|
|
let orgPoHasDraft = false;
|
|
await http
|
|
.get(config.API.isOrgPohasDraft)
|
|
.then((res) => {
|
|
orgPoHasDraft = res.data.result;
|
|
})
|
|
.catch((e) => {
|
|
messageError($q, e);
|
|
})
|
|
.finally(() => {
|
|
// hideLoader();
|
|
});
|
|
|
|
await http
|
|
.get(config.API.isOrghasDraft)
|
|
.then((res) => {
|
|
orgHasDraft = res.data.result;
|
|
})
|
|
.catch((e) => {
|
|
messageError($q, e);
|
|
})
|
|
.finally(() => {
|
|
// hideLoader();
|
|
});
|
|
|
|
if (orgHasDraft || orgPoHasDraft) {
|
|
version.value = "";
|
|
} else {
|
|
version.value = "published";
|
|
}
|
|
};
|
|
|
|
/**โหลด Tree Root Node
|
|
* @param isDraft แสดงข้อมูลดราฟหรือ Production
|
|
*/
|
|
const fetchTreeRoot = async (isDraft: boolean) => {
|
|
showLoader();
|
|
console.log("Call API14 GetTreeRoot");
|
|
isShowEditTree.value = isDraft; // to show same tree that we fetch
|
|
let request = "";
|
|
if (isDraft) {
|
|
request = config.API.getDraftTreeRoot;
|
|
} else {
|
|
request = config.API.getTreeRoot;
|
|
}
|
|
await http
|
|
.get(request)
|
|
.then((res) => {
|
|
if (isDraft) {
|
|
dataTreeDraft.value = res.data.result;
|
|
orgRootIdDraft.value = res.data.result[0].organizationId;
|
|
} else {
|
|
dataTree.value = res.data.result;
|
|
rootNodeKey.value = res.data.result[0].organizationId;
|
|
}
|
|
})
|
|
.catch((e) => {
|
|
// console.log(e);
|
|
// console.log(e.response);
|
|
manageApiErrorMsg(e);
|
|
// messageError($q, e);
|
|
})
|
|
.finally(() => {
|
|
hideLoader();
|
|
if (isDraft) {
|
|
// ถ้าไม่ต้องการให้แตก node root on first load ก็ไม่ต้องใส่
|
|
// ต้องอยู่ตรงนี้ ถ้าอยู่ตรง .then จะ error คาดว่ามันทำงานก่อนที่ tree จะ render เสร็จ แต่ก็อาจจะไม่ใช่
|
|
qtreeEdit.value.setExpanded(dataTreeDraft.value[0].keyId, true);
|
|
expandedNodeEdit.value = [dataTreeDraft.value[0].keyId];
|
|
} else {
|
|
qtreeView.value.setExpanded(dataTree.value[0].keyId, true);
|
|
}
|
|
});
|
|
};
|
|
|
|
/**โหลดลูก Tree
|
|
* @param node Parent Node
|
|
*/
|
|
const fetchChildrenByParentId = async (node: any) => {
|
|
// console.log(isDraft);
|
|
console.log("Call API4");
|
|
showLoader();
|
|
let request = "";
|
|
if (isShowEditTree.value) {
|
|
request = config.API.getDraftTreeNode(node.organizationId, node.keyId);
|
|
} else {
|
|
request = config.API.getTreeNode(node.organizationId, node.keyId);
|
|
}
|
|
|
|
await http
|
|
.get(request)
|
|
.then((res) => {
|
|
console.log(res.data.result);
|
|
node.children = res.data.result;
|
|
})
|
|
.catch((e) => {
|
|
// console.log(e);
|
|
// console.log(e.response);
|
|
manageApiErrorMsg(e);
|
|
})
|
|
.finally(() => {
|
|
hideLoader();
|
|
});
|
|
};
|
|
|
|
const fetchPublishFile = async () => {
|
|
showLoader();
|
|
await http
|
|
.get(config.API.getPublishFileHistory)
|
|
.then((res) => {
|
|
let data = res.data.result;
|
|
fileList.value = [];
|
|
data.map((e: any) => {
|
|
fileList.value.push({
|
|
value: e.fileName,
|
|
label: e.description,
|
|
});
|
|
});
|
|
selectedFile.value = fileList.value[0].value;
|
|
})
|
|
.catch((e) => {
|
|
messageError($q, e);
|
|
})
|
|
.finally(async () => {
|
|
hideLoader();
|
|
});
|
|
};
|
|
|
|
/**
|
|
* ฟังก์ชันสำหรับโหลด data tree ทีละชุด
|
|
* use by set @lazy-load="onLazyLoad" on q-tree
|
|
* @param node Auto send by Quasar Tree no need to send anything
|
|
*/
|
|
const onLazyLoad = (node: any) => {
|
|
setTimeout(async () => {
|
|
/**
|
|
* เรียก API4 มาแสดงผล ทีละ shot
|
|
*/
|
|
console.log("Call LazyLoad");
|
|
await fetchChildrenByParentId(node.node);
|
|
/** showLoader();
|
|
let request = "";
|
|
if (isShowEditTree.value) {
|
|
request = config.API.getDraftTreeNode(
|
|
node.node.organizationId,
|
|
node.node.keyId
|
|
);
|
|
} else {
|
|
//comment Jack's code
|
|
// if (node.node.organizationId == rootNodeKey.value) {
|
|
request = config.API.getTreeNode(
|
|
node.node.organizationId,
|
|
node.node.keyId
|
|
);
|
|
// } else {
|
|
// request = `https://s3cluster.frappet.com/bma-public-test/organization/strueture/${node.node.organizationId}-${node.node.organizationName}.json`;
|
|
// }
|
|
}
|
|
|
|
await http
|
|
.get(request)
|
|
.then((res) => {
|
|
// console.log(res.data.result);
|
|
//start Jack's code
|
|
// if (node.node.organizationId == rootNodeKey.value)
|
|
// node.node.children = res.data.result;
|
|
// else node.node.children = res.data;
|
|
//end Jack's code
|
|
node.node.children = res.data.result;
|
|
})
|
|
.catch((e) => {
|
|
// console.log(e);
|
|
// console.log(e.response);
|
|
manageApiErrorMsg(e);
|
|
// messageError($q, e);
|
|
})
|
|
.finally(() => {
|
|
hideLoader();
|
|
});*/
|
|
|
|
node.done(node.node.children); //return ค่าให้ q-tree generate children
|
|
}, 10);
|
|
};
|
|
|
|
/**====== Drawer Functions
|
|
* ========================
|
|
*/
|
|
const goToUserRegistry = () => {
|
|
router.push(`/registry/${personDetail.value.profileId}`);
|
|
};
|
|
|
|
/**
|
|
* ฟังก์ชันที่ดูข้อมูลผู้ใช้งานจาก tree
|
|
* @param node user ใน tree ที่จะดูข้อมูล (prop.node)
|
|
*/
|
|
const seeUserDetail = (node: any) => {
|
|
if (node.name != null) {
|
|
isChevronR.value = true;
|
|
isDrawer.value = true;
|
|
// personDetail.value = JSON.parse(JSON.stringify(node));
|
|
personDetail.value = node;
|
|
}
|
|
};
|
|
|
|
/**====== Pop-up Add/Edit/Delete Organization Functions
|
|
* ========================
|
|
*/
|
|
|
|
/**ลบหน่วยงานที่ตำแหน่งทั้งหมดที่มีว่างหมด
|
|
* Call API Delete when confirm
|
|
* @param node node that you want to delete (prop.node)
|
|
*/
|
|
const deleteOrganization = (node: any) => {
|
|
delStructureId.value = node.organizationId;
|
|
delStructureKey.value = node.keyId;
|
|
dialogMessage(
|
|
$q,
|
|
"ยืนยันลบหน่วยงาน",
|
|
"หากต้องการลบกดตกลง",
|
|
"mdi-help-circle-outline",
|
|
"ตกลง",
|
|
"red",
|
|
apiDeleteOrg,
|
|
undefined
|
|
);
|
|
};
|
|
const apiDeleteOrg = () => {
|
|
// const deleteOrganization = (node: any) => {
|
|
isShowEditTree.value = false;
|
|
// console.log("isShowEditTree", isShowEditTree.value);
|
|
setTimeout(async () => {
|
|
//delay for lazyLoad to be able to tricker again
|
|
showLoader();
|
|
isShowEditTree.value = true;
|
|
await http
|
|
.delete(config.API.delTreeOrgDraft(delStructureId.value))
|
|
.then((res) => {
|
|
success($q, "ลบข้อมูลสำเร็จ");
|
|
// console.log("delStructureKey", delStructureKey.value);
|
|
const nodeSplit = delStructureKey.value.split("-");
|
|
const nodeDelete = nodeSplit.splice(0, nodeSplit.length - 1);
|
|
const nodeJoin = nodeDelete.join("-");
|
|
// console.log("nodeJoin", nodeJoin);
|
|
qtreeEdit.value.setExpanded(nodeJoin, true);
|
|
})
|
|
.catch((e) => {
|
|
console.log(e);
|
|
console.log(e.response);
|
|
messageError($q, e);
|
|
})
|
|
.finally(async () => {
|
|
hideLoader();
|
|
await isTreeHasDraft();
|
|
});
|
|
}, 20);
|
|
};
|
|
|
|
/**ลบตำแหน่งที่ว่างออกจาก DB
|
|
* Call API Delete when confirm
|
|
* @param node node that you want to delete (prop.node)
|
|
*/
|
|
const deletePosition = (node: any) => {
|
|
delStructureId.value = node.organizationPositionId;
|
|
delStructureKey.value = node.keyId;
|
|
dialogMessage(
|
|
$q,
|
|
"ยืนยันลบตำแหน่ง",
|
|
"หากต้องการลบกดตกลง",
|
|
"mdi-help-circle-outline",
|
|
"ตกลง",
|
|
"red",
|
|
apiDeletePosition,
|
|
undefined
|
|
);
|
|
};
|
|
const apiDeletePosition = () => {
|
|
// const deletePosition = (node: any) => {
|
|
isShowEditTree.value = false;
|
|
setTimeout(async () => {
|
|
//delay for lazyLoad to be able to tricker again
|
|
showLoader();
|
|
isShowEditTree.value = true;
|
|
await http
|
|
.delete(config.API.delTreePositionDraft(delStructureId.value))
|
|
.then((res) => {
|
|
success($q, "ลบข้อมูลสำเร็จ");
|
|
const nodeSplit = delStructureKey.value.split("-");
|
|
const nodeDelete = nodeSplit.splice(0, nodeSplit.length - 1);
|
|
const nodeJoin = nodeDelete.join("-");
|
|
qtreeEdit.value.setExpanded(nodeJoin, true);
|
|
})
|
|
.catch((e) => {
|
|
console.log(e);
|
|
console.log(e.response);
|
|
messageError($q, e);
|
|
})
|
|
.finally(async () => {
|
|
hideLoader();
|
|
await isTreeHasDraft();
|
|
});
|
|
}, 20);
|
|
};
|
|
|
|
/**======ButtonSet Function
|
|
*==========================
|
|
*/
|
|
/**Delete Draft
|
|
* ฟังก์ชัน clear data แบบร่าง
|
|
*/
|
|
const deleteDraft = async () => {
|
|
showLoader();
|
|
await http
|
|
.put(config.API.delTreeOrgPoDraft)
|
|
.then((res) => {
|
|
success($q, "ลบข้อมูลร่างสำเร็จ");
|
|
})
|
|
.catch((e) => {
|
|
console.log(e);
|
|
console.log(e.response);
|
|
messageError($q, e);
|
|
})
|
|
.finally(async () => {
|
|
hideLoader();
|
|
router.go(0);
|
|
await isTreeHasDraft();
|
|
});
|
|
};
|
|
|
|
/**Publish Draft
|
|
* ฟังก์ชันเผยแพร่แบบร่าง
|
|
*/
|
|
const publishDraft = async () => {
|
|
showLoader();
|
|
await http
|
|
.put(config.API.publishOrgPoDraft)
|
|
.then((res) => {
|
|
success($q, "เผยแพร่ข้อมูลสำเร็จ");
|
|
//publish สำเร็จแล้ว ให้เช็คว่าถ้า BE generate file data เสร็จแล้วให้มีการเตือนให้ user reload viewTree ใหม่
|
|
//estimate time for be to regenerate new viewTree file is 30sec
|
|
//ยังไม่แน่ใจว่า BE จะ return success กลับมาเมื่อทำ publish สำเร็จ หรือเมื่อ generate new viewTree file เสร็จ
|
|
//ยูสเซอร์กด ตกลง ให้ Load viewTree ใหม่อีกครั้ง
|
|
dialogMessage(
|
|
$q,
|
|
"เผยแพร่ข้อมูลสำเร็จแล้ว",
|
|
"ต้องการโหลดข้อมูลใหม่หรือไม่",
|
|
"mdi-help-circle-outline",
|
|
"ตกลง",
|
|
"public",
|
|
loadViewTree,
|
|
undefined
|
|
);
|
|
})
|
|
.catch((e) => {
|
|
console.log(e);
|
|
console.log(e.response);
|
|
messageError($q, e);
|
|
})
|
|
.finally(async () => {
|
|
hideLoader();
|
|
await isTreeHasDraft();
|
|
});
|
|
};
|
|
|
|
/**Refresh Data
|
|
* clear Loacal Storage
|
|
* reload root tree
|
|
* reload สำนัก
|
|
* ไม่ใช้แล้ว ยังไม่ลบเพราะไม่รู้เป้จะอยากได้อีกไหม
|
|
*/
|
|
const resetTree = async () => {
|
|
dialogMessage(
|
|
$q,
|
|
"รีเฟรชหน้า",
|
|
"ต้องการรีเฟรชผังโครงสร้างใหม่หรือไม่",
|
|
"mdi-help-circle-outline",
|
|
"ตกลง",
|
|
"public",
|
|
loadPublishScreen,
|
|
undefined
|
|
);
|
|
}; //ไม่ใช้แล้ว ยังไม่ลบเพราะไม่รู้เป้จะอยากได้อีกไหม
|
|
const clearLocalStorage = async () => {
|
|
localStorage.removeItem("dataTree");
|
|
}; //ไม่ใช้แล้ว ยังไม่ลบเพราะไม่รู้เป้จะอยากได้อีกไหม
|
|
|
|
/**====== Tree Functions
|
|
* ========================
|
|
*/
|
|
const resetFilter = () => {
|
|
// reset ค่าที่ค้นหาเมื่อกดปุ่ม X ในกล่องค้นหา
|
|
treeFilter.value = ""; // v-model="treeFilter"
|
|
treeFilterRef.value.focus(); // ref="treeFilterRef"
|
|
}; //reset Tree Filter
|
|
|
|
/**Search Tree Function
|
|
* :filter="treeFilter" - input box v-model name
|
|
* :filter-method="treeFilterMethod"
|
|
* @param node tree node Auto send by quasar tree
|
|
* @param filter searching word Auto send by quasar tree
|
|
*/
|
|
const treeFilterMethod = (node: any, filter: string) => {
|
|
const filt = filter;
|
|
let hasMatch =
|
|
(node.organizationName && node.organizationName.indexOf(filt) > -1) ||
|
|
(node.positionNum && node.positionNum.indexOf(filt) > -1) ||
|
|
(node.name && node.name.indexOf(filt) > -1) ||
|
|
(node.positionName && node.positionName.indexOf(filt) > -1) ||
|
|
(node.governmentCode &&
|
|
node.governmentCode.toString().indexOf(filt) > -1) ||
|
|
(node.agency && node.agency.indexOf(filt) > -1) ||
|
|
(node.government && node.government.indexOf(filt) > -1) ||
|
|
(node.department && node.department.indexOf(filt) > -1) ||
|
|
(node.pile && node.pile.indexOf(filt) > -1) ||
|
|
(node.organizationShortName &&
|
|
node.organizationShortName.indexOf(filt) > -1) ||
|
|
(node.positionSideName && node.positionSideName.indexOf(filt) > -1) ||
|
|
(node.executivePosition && node.executivePosition.indexOf(filt) > -1) ||
|
|
(node.executivePositionSide &&
|
|
node.executivePositionSide.indexOf(filt) > -1) ||
|
|
(node.positionLevel && node.positionLevel.indexOf(filt) > -1);
|
|
|
|
//hasMatch จะได้เป็น keyId ของ node ที่หาเจอโดย q-tree จะวนเรียก treeFilterMethod ทีละ node
|
|
//ถ้า 100 nodes ก็วนฟังชั่นนี้ 100 รอบ
|
|
//ยังไม่ใช้ เพราะเรียก api มาทีละ level user จะค่อยๆ แตก tree ออกมาอยู่แล้ว
|
|
// if (hasMatch) {
|
|
// // if the current node matches the filter, expand all nodes in the tree
|
|
// expandedNode.value.push(node.keyId);
|
|
// //expandAllNodes([node]);
|
|
// }
|
|
|
|
return hasMatch;
|
|
};
|
|
|
|
/**Add โครงสร้าง Org & Position
|
|
* API1
|
|
* @param node node that you want to add children data
|
|
*/
|
|
const addStructure = async (node: any) => {
|
|
isShowEditTree.value = false; //ซ่อน editTree เพื่อให้สามารถเรียก lazyLoad ได้อีกครั้งเมื่อกลับมาแสดง
|
|
// console.log(node);
|
|
console.log("organizationData.value", organizationData.value);
|
|
// console.log("organizationForm.value", organizationForm.value);
|
|
console.log("positionData.value", positionData.value);
|
|
let organizCheck: Boolean = false;
|
|
let positionCheck: Boolean = false;
|
|
await organizationForm.value
|
|
?.validate()
|
|
.then((e: Boolean) => (organizCheck = e));
|
|
await positionForm.value
|
|
?.validate()
|
|
.then((e: Boolean) => (positionCheck = e));
|
|
// if (positionData.value.length <= 0 && organizationData.value.length <= 0) {
|
|
// popupAddOrganization.value = false;
|
|
// } // no data to add close pop-up no message show when click save
|
|
if (
|
|
organizCheck == true &&
|
|
(positionCheck == true || modalHeaderPosition.value == false) &&
|
|
(positionData.value.length > 0 || organizationData.value.length > 0)
|
|
) {
|
|
let reqOrgAr: Array<any> = JSON.parse(
|
|
JSON.stringify(organizationData.value)
|
|
);
|
|
reqOrgAr.forEach((a: any) => {
|
|
delete a["organizationShortName"];
|
|
delete a["organizationShortCode"];
|
|
a.organizationId = node.organizationId; //parentId ของ node ที่จะสร้าง
|
|
});
|
|
// console.log(node.organizationId);
|
|
console.log("Call API1");
|
|
showLoader();
|
|
isShowEditTree.value = true; //ต้องกลับมาแสดง editTree อีกครั้ง & trigger lazyLoad โดย setExpanded
|
|
await http
|
|
.post(config.API.addTreeDraft, {
|
|
organizationId: node.organizationId, // GUID ของหน่วยงานต้นสังกัดที่ต้องการสร้างข้อมูล, // ParentId ของ Org ที่จะเพิ่มใหม่
|
|
organizations: reqOrgAr,
|
|
positions: positionData.value, // รอต่อ api dropdown ตำแหน่งก่อน
|
|
})
|
|
.then(async (res) => {
|
|
success($q, "บันทึกข้อมูลร่างสำเร็จ");
|
|
|
|
//reload it's own node to see new added nodes
|
|
qtreeEdit.value.setExpanded(node.keyId, true);
|
|
})
|
|
|
|
.catch((e) => {
|
|
console.log(e);
|
|
console.log(e.response);
|
|
messageError($q, e);
|
|
})
|
|
.finally(async () => {
|
|
hideLoader();
|
|
|
|
popupAddOrganization.value = false;
|
|
await isTreeHasDraft();
|
|
});
|
|
} else {
|
|
console.log("validation fail"); // or no data to add");
|
|
}
|
|
isShowEditTree.value = true;
|
|
};
|
|
|
|
/**Edit โครงสร้างหน่วยงาน
|
|
* API13
|
|
* @param node node that you want to edit data
|
|
*/
|
|
const editOrgStructure = async (node: any) => {
|
|
isShowEditTree.value = false; //start prepare for tricker LazyLoad
|
|
// console.log(node);
|
|
// console.log("organizationData.value", organizationData.value);
|
|
let organizCheck: Boolean = false;
|
|
|
|
await organizationForm.value
|
|
?.validate()
|
|
.then((e: Boolean) => (organizCheck = e));
|
|
// if (organizationData.value.length <= 0) {
|
|
// popupAddOrganization.value = false;
|
|
// } // no data to add close pop-up when click save no message show
|
|
console.log("organizCheck=>", organizCheck);
|
|
// console.log("organizationData.value.length=>", organizationData.value.length);
|
|
if (organizCheck == true) {
|
|
// console.log(node.organizationId);
|
|
console.log("Call API13");
|
|
showLoader();
|
|
isShowEditTree.value = true; //end prepare for tricker LazyLoad
|
|
await http
|
|
.put(config.API.editTreeOrgDraft(node.organizationId), {
|
|
organizationId: node.organizationId, // GUID ของหน่วยงานที่ต้องการแก้ไขข้อมูล มีส่งไปใน uri ด้วย
|
|
organizationOrganizationId:
|
|
organizationDataEdit.value?.organizationOrganizationId,
|
|
organizationShortNameId:
|
|
organizationDataEdit.value?.organizationShortNameId,
|
|
organizationTypeId: organizationDataEdit.value?.organizationTypeId,
|
|
organizationLevelId: organizationDataEdit.value?.organizationLevelId,
|
|
organizationTelExternalId:
|
|
organizationDataEdit.value?.organizationExternalPhoneId,
|
|
organizationTelInternalId:
|
|
organizationDataEdit.value?.organizationInternalPhoneId,
|
|
organizationFaxId: organizationDataEdit.value?.organizationFaxId,
|
|
organizationOrder: organizationDataEdit.value?.organizationOrder,
|
|
organizationUserNote: organizationDataEdit.value?.organizationUserNote,
|
|
agency: organizationDataEdit.value?.agency,
|
|
government: organizationDataEdit.value?.government,
|
|
department: organizationDataEdit.value?.department,
|
|
pile: organizationDataEdit.value?.pile,
|
|
organizationStatusId: organizationDataEdit.value?.organizationStatusId,
|
|
isActive: organizationDataEdit.value?.isActive,
|
|
})
|
|
.then(async (res) => {
|
|
success($q, "บันทึกข้อมูลร่างสำเร็จ");
|
|
|
|
//reload children nodes by setExpanded mother node
|
|
const nodeSplit = await node.keyId.split("-");
|
|
const nodeDelete = await nodeSplit.splice(0, nodeSplit.length - 1);
|
|
const nodeJoin = await nodeDelete.join("-");
|
|
qtreeEdit.value.setExpanded(nodeJoin, true);
|
|
})
|
|
.catch((e) => {
|
|
console.log(e);
|
|
console.log(e.response);
|
|
messageError($q, e);
|
|
})
|
|
.finally(async () => {
|
|
hideLoader();
|
|
popupEditSelectedOrganization.value = false;
|
|
await isTreeHasDraft();
|
|
});
|
|
} else {
|
|
console.log("validation fail"); // or no data to add");
|
|
}
|
|
isShowEditTree.value = true;
|
|
};
|
|
|
|
/**Edit ตำแหน่ง ในโครงสร้าง
|
|
* API3
|
|
* @param node node that you want to edit data
|
|
*/
|
|
const editPositionStructure = async (node: any) => {
|
|
isShowEditTree.value = false; //start prepare for tricker LazyLoad
|
|
// console.log("positionData.value", positionData.value);
|
|
// console.log("Selectednode.keyId", node.keyId);
|
|
// console.log("PrarentNode.keyId", node.keyId.slice(0, -2));
|
|
let positionCheck: Boolean = false;
|
|
await positionForm.value
|
|
?.validate()
|
|
.then((e: Boolean) => (positionCheck = e));
|
|
|
|
if (positionCheck == true) {
|
|
console.log("Call API3");
|
|
showLoader();
|
|
isShowEditTree.value = true; //end prepare for tricker LazyLoad
|
|
await http
|
|
.put(config.API.editTreePositionDraft(node.organizationPositionId), {
|
|
positionMasterId: positionData.value[0].positionMasterId,
|
|
positionUserNote: positionData.value[0].positionUserNote,
|
|
isActive: positionData.value[0].isActive,
|
|
isCondition: positionData.value[0].isCondition,
|
|
conditionNote: positionData.value[0].conditionNote,
|
|
})
|
|
.then(async (res) => {
|
|
success($q, "บันทึกข้อมูลร่างสำเร็จ");
|
|
|
|
//reload children nodes by setExpanded mother node
|
|
const nodeSplit = await node.keyId.split("-");
|
|
const nodeDelete = await nodeSplit.splice(0, nodeSplit.length - 1);
|
|
const nodeJoin = await nodeDelete.join("-");
|
|
qtreeEdit.value.setExpanded(nodeJoin, true);
|
|
})
|
|
.catch((e) => {
|
|
messageError($q, e);
|
|
})
|
|
.finally(async () => {
|
|
hideLoader();
|
|
popupEditSelectedPosition.value = false;
|
|
await isTreeHasDraft();
|
|
});
|
|
} else {
|
|
console.log("validation fail"); // or no data to add");
|
|
}
|
|
isShowEditTree.value = true;
|
|
};
|
|
|
|
/**ฟังชั้นดูข้อมูลประวัติแก้ไขข้อมูลที่เลือก
|
|
*/
|
|
const clickHistory = async () => {
|
|
modalHistory.value = true;
|
|
// rowsHistory.value = rawHistory.value.filter((f: any) => f.id == row.id);
|
|
|
|
showLoader();
|
|
await http
|
|
.get(config.API.getTreeHistory)
|
|
.then((res) => {
|
|
let data = res.data.result;
|
|
rowsHistory.value = [];
|
|
// version.value = "published";
|
|
data.map((e: any) => {
|
|
rowsHistory.value.push({
|
|
detail: e.detail,
|
|
editUser: e.createdFullName,
|
|
editDate: e.createdAt,
|
|
});
|
|
// if (e.isPublished == false) {
|
|
// version.value = "draft";
|
|
// }
|
|
});
|
|
})
|
|
.catch((e) => {
|
|
rowsHistory.value.splice(0);
|
|
manageApiErrorMsg(e);
|
|
// messageError($q, e);
|
|
})
|
|
.finally(() => {
|
|
hideLoader();
|
|
});
|
|
};
|
|
|
|
/**Check Error Code 404 before return error message
|
|
* Data not found is not error for GET method so do nothing
|
|
* @param catchE throw catch error message (e)
|
|
*/
|
|
const manageApiErrorMsg = (catchE: any) => {
|
|
if (catchE.response.status == 404 || catchE.response.data.status == 404) {
|
|
//Data not found is not error for GET method so do nothing
|
|
return;
|
|
// } else if (
|
|
// catchE.response.data.status == 400 ||
|
|
// catchE.response.data.status == 403 ||
|
|
// catchE.response.data.status == 404
|
|
// ) {
|
|
// //ใส่เป็น error กลางๆ ถ้ามีเคสให้เห็นมากขึ้น ถึงจะแยกข้อความได้
|
|
// modalError(q, "พบข้อผิดพลาด", "ไม่พบข้อมูล");
|
|
} else {
|
|
messageError($q, catchE);
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style>
|
|
.pointer:hover {
|
|
cursor: pointer;
|
|
background-color: #f4f4f4;
|
|
}
|
|
|
|
.q-tree__node-header {
|
|
padding: 0px;
|
|
margin-top: 0px;
|
|
border-radius: 4px;
|
|
outline: 0;
|
|
}
|
|
/* .q-tree__node--selected .q-tree__node-header-content {
|
|
border: 1px solid #02a998c0;
|
|
border-radius: 4px;
|
|
} */
|
|
.topCard {
|
|
z-index: 50;
|
|
position: absolute;
|
|
left: 35px;
|
|
}
|
|
.my-custom-toggle {
|
|
border: 1px solid #02a998;
|
|
}
|
|
.pageSK {
|
|
z-index: 30;
|
|
}
|
|
/* mouse over link */
|
|
.abc:hover {
|
|
color: #ff00ff;
|
|
}
|
|
.btn-absolute {
|
|
z-index: 50;
|
|
position: absolute;
|
|
left: 200px;
|
|
top: 30px;
|
|
}
|
|
.q-header {
|
|
z-index: 40;
|
|
}
|
|
.page-relative {
|
|
position: relative;
|
|
}
|
|
|
|
.my-list {
|
|
padding: 10px 10px;
|
|
}
|
|
|
|
.my-card {
|
|
width: 100%;
|
|
max-width: 160px;
|
|
}
|
|
|
|
.sub-card {
|
|
height: 100%;
|
|
max-height: 265px;
|
|
}
|
|
|
|
.cardNum {
|
|
border-radius: 5px;
|
|
}
|
|
|
|
.fc-direction-ltr .fc-daygrid-event.fc-event-end,
|
|
.fc-direction-rtl .fc-daygrid-event.fc-event-start {
|
|
padding-left: 5px;
|
|
}
|
|
|
|
.btnShadow {
|
|
box-shadow: 0 1px 2px rgb(0 0 0 / 10%), 3px 3px 7px 1px rgba(95, 95, 95, 0.15) !important;
|
|
}
|
|
.texttop {
|
|
font-size: 18px;
|
|
font-weight: 500;
|
|
}
|
|
.textSub {
|
|
font-size: 0.8rem;
|
|
}
|
|
.btnline {
|
|
border: 1px solid #c8d3dba4;
|
|
}
|
|
.q-tree {
|
|
color: #c8d3db;
|
|
}
|
|
</style>
|