hrms-admin/src/modules/02_users/views/page02_rolesAndPermissionsDetail.vue
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 f325b30a76 fix: default isAdminVisibled
2025-11-12 09:41:18 +07:00

814 lines
29 KiB
Vue

<script setup lang="ts">
import { onMounted, reactive, ref } from "vue";
import { useQuasar } from "quasar";
import { useRouter, useRoute } from "vue-router";
import http from "@/plugins/http";
import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin";
import type {
DataOption,
SystemList,
DataSystem,
} from "@/modules/02_users/interface/index/Main";
import type { SysList } from "@/modules/02_users/interface/response/Main";
import type { FormRole } from "@/modules/02_users/interface/request/Main";
/** use*/
const router = useRouter();
const route = useRoute();
const $q = useQuasar();
const { dialogConfirm, messageError, showLoader, hideLoader, success } =
useCounterMixin();
const roleId = ref<string>(route.params.id.toString()); // id บทบาท
// รายการสิทธิ์การเข้าถึง
const attrPrivilegeOp = ref<DataOption[]>([
{
id: "ROOT",
name: "มีสิทธิ์เข้าถึงข้อมูลในทุกระดับ",
},
{
id: "PARENT",
name: "มีสิทธิ์เข้าถึงข้อมูลในทุกระดับที่อยู่ภายใต้หน่วยงานของตัวเอง ยกเว้นระดับชั้นบนสุด",
},
{
id: "CHILD",
name: "มีสิทธิ์เข้าถึงข้อมูลเฉพาะระดับชั้นปัจจุบันของตัวเอง",
},
{
id: "NORMAL",
name: "มีสิทธิ์เข้าถึงข้อมูลเฉพาะในระดับชั้นตัวเองเท่านั้น",
},
{
id: "SPECIFIC",
name: "มีสิทธิ์เข้าถึงข้อมูลเฉพาะเจาะจง",
},
]);
// ฟอร์มบทบาท
const formData = reactive<FormRole>({
roleName: "", // ชื่อบทบาม
roleDescription: "", // คำอธิบาย
isAdminVisibled: false, // แสดงผลในหน้าผู้ดูแลระบบ
});
const sysListMain = ref<SysList[]>([]);
const systemLists = ref<SystemList[]>([]);
/**
* ดึงข้อมูลรายการระบบทั้หมด
*/
async function fetchSys() {
showLoader();
await http
.get(config.API.managementSysList)
.then(async (res) => {
sysListMain.value = await res.data.result;
await fetchDataRole();
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/**
* ดึงข้อมูลบทบาทและสิทธิ์
*
* บันทึกข้อมูลสิทธิ์เข้ากับรายการระบบ
*/
async function fetchDataRole() {
showLoader();
await http
.get(config.API.managementAuth + `/${roleId.value}`)
.then(async (res) => {
const data = await res.data.result;
const sysList = data.roleAttributes;
formData.roleName = data.roleName;
formData.roleDescription = data.roleDescription;
formData.isAdminVisibled = data.isAdminVisibled
? data.isAdminVisibled
: false;
const root: SystemList[] = [];
const chil: SystemList[] = [];
sysListMain.value.forEach((item: any) => {
if (item.children.length !== 0) {
item.children.forEach((q: SystemList) => {
const findChil = sysList.find(
(e: DataSystem) => e.authSysId === q.id
);
chil.push({
...q,
selected: findChil ? true : false,
attrOwnership: findChil ? findChil.attrOwnership : "",
attrIsCreate: findChil ? findChil.attrIsCreate : false,
attrIsList: findChil ? findChil.attrIsList : false,
attrIsGet: findChil ? findChil.attrIsGet : false,
attrIsUpdate: findChil ? findChil.attrIsUpdate : false,
attrIsDelete: findChil ? findChil.attrIsDelete : false,
attrPrivilege: findChil ? findChil.attrPrivilege : "",
});
});
const findMainRoot = sysList.find(
(e: DataSystem) => e.parentNode === item.id
);
const arrayChil = chil.filter((a) => a.parentId === item.id);
if (arrayChil) {
root.push({
...item,
selected: findMainRoot ? true : false,
attrOwnership: "",
attrIsCreate: false,
attrIsList: false,
attrIsGet: false,
attrIsUpdate: false,
attrIsDelete: false,
attrPrivilege: "",
children: arrayChil,
});
}
} else {
const findRoot = sysList.find(
(e: DataSystem) => e.authSysId === item.id
);
root.push({
...item,
selected: findRoot ? true : false,
attrOwnership: findRoot ? findRoot.attrOwnership : "",
attrIsCreate: findRoot ? findRoot.attrIsCreate : false,
attrIsList: findRoot ? findRoot.attrIsList : false,
attrIsGet: findRoot ? findRoot.attrIsGet : false,
attrIsUpdate: findRoot ? findRoot.attrIsUpdate : false,
attrIsDelete: findRoot ? findRoot.attrIsDelete : false,
attrPrivilege: findRoot ? findRoot.attrPrivilege : "",
});
}
});
systemLists.value = root;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/**
* ยืนยันการบันทึกการบทบาทและสิทธิ์
*/
function onSubmit() {
dialogConfirm($q, () => {
showLoader();
const filterList: any = systemLists.value.filter(
(e: any) => e.selected === true
);
const arrayRoleAttrs = filterList.flatMap((e: any) => {
if (e.children.length === 0) {
return {
parentNode: e.id,
attrPrivilege: e.attrPrivilege,
attrIsDelete: e.attrIsDelete,
attrIsUpdate: e.attrIsUpdate,
attrIsGet: e.attrIsGet,
attrIsList: e.attrIsList,
attrIsCreate: e.attrIsCreate,
attrOwnership: e.attrOwnership,
authSysId: e.id,
};
} else {
const filterListChil = e.children.filter(
(e: any) =>
e.selected === true &&
e.attrOwnership !== "" &&
e.attrPrivilege !== ""
);
return filterListChil.map((i: any) => ({
parentNode: e.id,
attrPrivilege: i.attrPrivilege,
attrIsDelete: i.attrIsDelete,
attrIsUpdate: i.attrIsUpdate,
attrIsGet: i.attrIsGet,
attrIsList: i.attrIsList,
attrIsCreate: i.attrIsCreate,
attrOwnership: i.attrOwnership,
authSysId: i.id,
}));
}
});
const body = {
...formData,
authRoleAttrs: arrayRoleAttrs,
};
http
.patch(config.API.managementAuth + `/${roleId.value}`, body)
.then(async () => {
await fetchDataRole();
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
});
}
function onHandleChangeIsAdminVisibled(val: boolean) {
if (val === true) {
systemLists.value.forEach((system: SystemList) => {
if (system.selected && system.attrOwnership === "OWNER") {
system.attrOwnership = "STAFF";
system.attrIsCreate = system.attrIsCreate;
system.attrIsList = system.attrIsList;
system.attrIsGet = system.attrIsGet;
system.attrIsUpdate = system.attrIsUpdate;
system.attrIsDelete = system.attrIsDelete;
system.attrPrivilege = system.attrPrivilege;
}
if (system.children && system.children.length > 0) {
system.children.forEach((child: SystemList) => {
if (child.selected && child.attrOwnership === "OWNER") {
child.attrOwnership = "STAFF";
child.attrIsCreate = child.attrIsCreate;
child.attrIsList = child.attrIsList;
child.attrIsGet = child.attrIsGet;
child.attrIsUpdate = child.attrIsUpdate;
child.attrIsDelete = child.attrIsDelete;
child.attrPrivilege = child.attrPrivilege;
}
});
}
});
}
}
/**
* hook ทำงานเมื่อมีการเรียกใช้ components
*
* โหลดข้อมูลรายการระบบทั้งหมด
*/
onMounted(async () => {
fetchSys();
});
</script>
<template>
<div class="toptitle col-12 row items-center">
<q-btn
icon="mdi-arrow-left"
unelevated
round
dense
flat
color="primary"
class="q-mr-sm"
@click="router.go(-1)"
/>
ดการบทบาทและสทธ
</div>
<q-form greedy @submit.prevent @validation-success="onSubmit">
<q-card flast bordered>
<div class="col-12">
<q-card>
<q-card-section>
<div class="row q-col-gutter-md">
<div class="row col-4">
<div class="col-12">
<q-input
v-model="formData.roleName"
outlined
dense
:rules="[(val:string) => !!val || `${'กรุณากรอกชื่อบทบาท'}`,]"
lazy-rules
hide-bottom-space
class="inputgreen"
label="ชื่อบทบาท"
/>
</div>
<div class="col-12">
<q-toggle
color="primary"
class="q-pr-md"
v-model="formData.isAdminVisibled"
label="ผู้ดูแลระบบมองเห็น"
@update:model-value="onHandleChangeIsAdminVisibled"
/>
</div>
</div>
<div class="col-8">
<q-input
v-model="formData.roleDescription"
outlined
dense
lazy-rules
hide-bottom-space
class="inputgreen"
label="คำอธิบาย"
type="textarea"
/>
</div>
</div>
</q-card-section>
</q-card>
</div>
<div class="col-12">
<q-table
class="my-sticky-dynamic"
virtual-scroll
flat
bordered
:rows="systemLists"
separator="cell"
:pagination="{
page: 1,
rowsPerPage: 100,
}"
hide-bottom
>
<template v-slot:header>
<q-tr>
<q-th rowspan="2" colspan="3" style="font-size: 1rem"
>รายการระบบ</q-th
>
<q-th colspan="3" style="font-size: 1rem"
>ความเป็นเจ้าของ (Ownership)</q-th
>
<q-th colspan="5" style="text-align: center; font-size: 1rem"
>สิทธิ์ดำเนินการ (Permission)</q-th
>
<q-th
class="relative-position"
colspan="2"
rowspan="2"
style="text-align: center; font-size: 1rem"
>สิทธิ์การเข้าถึง<br />
(Privilege)
<q-btn
class="absolute-customH"
color="grey-4"
round
icon="info"
flat
size="12px"
><q-tooltip class="text-body1">
<div class="column">
<div class="row no-wrap">
<strong>ROOT</strong>-มีสิทธิ์เข้าถึงข้อมูลในทุกระดับ
ตั้งแต่ระดับของตัวเองลงไปชั้นล่างสุด
และขึ้นไปถึงชั้นบนสุด
</div>
<div class="row no-wrap">
<strong>PARENT</strong
>-มีสิทธิ์เข้าถึงข้อมูลในทุกระดับที่อยู่ภายใต้หน่วยงานของตัวเอง
ยกเว้นระดับชั้นบนสุด
</div>
<div class="row no-wrap">
<strong>CHILD</strong
>-มีสิทธิ์เข้าถึงข้อมูลเฉพาะระดับชั้นปัจจุบันของตัวเอง
ลงไปถึงชั้นล่างสุด
</div>
<div class="row no-wrap">
<strong>NORMAL</strong
>-มีสิทธิ์เข้าถึงข้อมูลเฉพาะในระดับชั้นตัวเองเท่านั้น
ไม่สามารถขึ้นหรือลงได้
</div>
<div class="row no-wrap">
<strong>SPECIFIC</strong
>-มีสิทธิ์เข้าถึงข้อมูลเฉพาะเจาะจง ซึ่งจะต้องกำหนด ID
ของข้อมูลที่ต้องการเข้าถึงด้วย
</div>
</div>
</q-tooltip></q-btn
></q-th
>
</q-tr>
<q-tr>
<q-th class="relative-position"
>OWNER
<q-btn
class="absolute-custom"
color="grey-4"
round
icon="info"
flat
size="10px"
><q-tooltip class="text-body2">
เป็นเจ้าของระบบ มีสิทธิ์เต็มที่จะทำทุกอย่างในระบบนั้น ๆ
ได้ทั้งหมดทุกหน่วยงานโดยไม่สนใจสิทธิ์และลำดับชั้นการเข้าถึง
</q-tooltip></q-btn
>
</q-th>
<q-th class="relative-position"
>STAFF
<q-btn
class="absolute-custom"
color="grey-4"
round
icon="info"
flat
size="10px"
><q-tooltip class="text-body2">
เป็นเจ้าหน้าที่
ซึ่งอาจจะมีสิทธิ์ในการเข้าใช้ระบบได้เพียงอย่างใดอย่างหนึ่งหรือทั้งหมด
ทั้งนี้ขึ้นกับสิทธิ์และลำดับชั้นการเข้าถึง
</q-tooltip></q-btn
></q-th
>
<q-th class="relative-position"
>GUEST
<q-btn
class="absolute-custom"
color="grey-4"
round
icon="info"
flat
size="10px"
><q-tooltip class="text-body2">
เป็นผู้มาเยือน ใช้ในกรณีกำหนดบทบาทชั่วคราว และบทบาทเฉพาะกิจ
</q-tooltip></q-btn
></q-th
>
<q-th class="relative-position"
>CREATE
<q-btn
class="absolute-custom"
color="grey-4"
round
icon="info"
flat
size="10px"
><q-tooltip class="text-body2">
มีสิทธิ์ในการสร้างข้อมูล
</q-tooltip></q-btn
></q-th
>
<q-th class="relative-position"
>LIST
<q-btn
class="absolute-custom"
color="grey-4"
round
icon="info"
flat
size="10px"
><q-tooltip class="text-body2">
มีสิทธิ์ในการดูรายการข้อมูล
</q-tooltip></q-btn
></q-th
>
<q-th class="relative-position"
>GET
<q-btn
class="absolute-custom"
color="grey-4"
round
icon="info"
flat
size="10px"
><q-tooltip class="text-body2">
มีสิทธิ์ในการดูรายละเอียดข้อมูล
</q-tooltip></q-btn
></q-th
>
<q-th class="relative-position"
>UPDATE
<q-btn
class="absolute-custom"
color="grey-4"
round
icon="info"
flat
size="10px"
><q-tooltip class="text-body2">
มีสิทธิ์ในการแก้ไขข้อมูล
</q-tooltip></q-btn
></q-th
>
<q-th class="relative-position"
>DELETE
<q-btn
class="absolute-custom"
color="grey-4"
round
icon="info"
flat
size="10px"
><q-tooltip class="text-body2">
มีสิทธิ์ในการลบข้อมูล
</q-tooltip></q-btn
></q-th
>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr>
<q-td auto-width colspan="3">
<q-checkbox
v-model="props.row.selected"
@update:model-value="
!props.row.selected && (props.row.attrOwnership = ''),
(props.row.attrIsCreate = false),
(props.row.attrIsList = false),
(props.row.attrIsGet = false),
(props.row.attrIsUpdate = false),
(props.row.attrIsDelete = false),
(props.row.attrPrivilege = '')
"
/>
<strong>{{ props.row.sysName }}</strong>
</q-td>
<q-td style="text-align: center">
<q-radio
v-model="props.row.attrOwnership"
val="OWNER"
@update:model-value="
props.row.attrOwnership === 'OWNER' &&
(props.row.attrIsCreate = true),
(props.row.attrIsList = true),
(props.row.attrIsGet = true),
(props.row.attrIsUpdate = true),
(props.row.attrIsDelete = true),
(props.row.attrPrivilege = 'ROOT')
"
v-if="props.row.children.length === 0"
:disable="!props.row.selected || formData.isAdminVisibled"
/>
</q-td>
<q-td style="text-align: center">
<q-radio
v-model="props.row.attrOwnership"
val="STAFF"
v-if="props.row.children.length === 0"
:disable="!props.row.selected"
/>
</q-td>
<q-td style="text-align: center">
<q-radio
v-model="props.row.attrOwnership"
val="GUEST"
v-if="props.row.children.length === 0"
:disable="!props.row.selected"
/>
</q-td>
<q-td style="text-align: center">
<q-checkbox
v-model="props.row.attrIsCreate"
v-if="props.row.children.length === 0"
:disable="
!props.row.selected ||
(props.row.selected && props.row.attrOwnership === 'OWNER')
"
/>
</q-td>
<q-td style="text-align: center">
<q-checkbox
v-model="props.row.attrIsList"
v-if="props.row.children.length === 0"
:disable="
!props.row.selected ||
(props.row.selected && props.row.attrOwnership === 'OWNER')
"
/>
</q-td>
<q-td style="text-align: center">
<q-checkbox
v-model="props.row.attrIsGet"
v-if="props.row.children.length === 0"
:disable="
!props.row.selected ||
(props.row.selected && props.row.attrOwnership === 'OWNER')
"
/>
</q-td>
<q-td style="text-align: center">
<q-checkbox
v-model="props.row.attrIsUpdate"
v-if="props.row.children.length === 0"
:disable="
!props.row.selected ||
(props.row.selected && props.row.attrOwnership === 'OWNER')
"
/>
</q-td>
<q-td style="text-align: center">
<q-checkbox
v-model="props.row.attrIsDelete"
v-if="props.row.children.length === 0"
:disable="
!props.row.selected ||
(props.row.selected && props.row.attrOwnership === 'OWNER')
"
/>
</q-td>
<q-td style="min-width: 120px">
<q-select
v-if="props.row.children.length === 0"
v-model="props.row.attrPrivilege"
:options="attrPrivilegeOp"
option-value="id"
option-label="id"
emit-value
map-options
dense
outlined
:disable="
!props.row.selected ||
(props.row.selected && props.row.attrOwnership === 'OWNER')
"
label="สิทธิ์เข้าถึงข้อมูล"
style="min-width: 120px"
:rules="[(val:string) => !!val || `${'กรุณาเลือกสิทธิ์เข้าถึงข้อมูล'}`,]"
>
</q-select>
</q-td>
</q-tr>
<q-tr
v-if="props.row.selected && props.row.children"
v-for="(item, index) in props.row.children"
:key="index"
>
<q-td></q-td>
<q-td auto-width colspan="2">
<q-checkbox
v-model="item.selected"
@update:model-value="
!item.selected && (item.attrOwnership = ''),
(item.attrIsCreate = false),
(item.attrIsList = false),
(item.attrIsGet = false),
(item.attrIsUpdate = false),
(item.attrIsDelete = false),
(item.attrPrivilege = '')
"
/>
{{ item.sysName }}
</q-td>
<q-td style="text-align: center">
<q-radio
v-model="item.attrOwnership"
val="OWNER"
@update:model-value="
item.attrOwnership === 'OWNER' &&
(item.attrIsCreate = true),
(item.attrIsList = true),
(item.attrIsGet = true),
(item.attrIsUpdate = true),
(item.attrIsDelete = true),
(item.attrPrivilege = 'ROOT')
"
:disable="!item.selected || formData.isAdminVisibled"
/>
</q-td>
<q-td style="text-align: center">
<q-radio
v-model="item.attrOwnership"
val="STAFF"
:disable="!item.selected"
/>
</q-td>
<q-td style="text-align: center">
<q-radio
v-model="item.attrOwnership"
val="GUEST"
:disable="!item.selected"
/>
</q-td>
<q-td style="text-align: center">
<q-checkbox
v-model="item.attrIsCreate"
:disable="
!item.selected ||
(item.selected && item.attrOwnership === 'OWNER')
"
/>
</q-td>
<q-td style="text-align: center">
<q-checkbox
v-model="item.attrIsList"
:disable="
!item.selected ||
(item.selected && item.attrOwnership === 'OWNER')
"
/>
</q-td>
<q-td style="text-align: center">
<q-checkbox
v-model="item.attrIsGet"
:disable="
!item.selected ||
(item.selected && item.attrOwnership === 'OWNER')
"
/>
</q-td>
<q-td style="text-align: center">
<q-checkbox
v-model="item.attrIsUpdate"
:disable="
!item.selected ||
(item.selected && item.attrOwnership === 'OWNER')
"
/>
</q-td>
<q-td style="text-align: center">
<q-checkbox
v-model="item.attrIsDelete"
:disable="
!item.selected ||
(item.selected && item.attrOwnership === 'OWNER')
"
/>
</q-td>
<q-td style="min-width: 120px">
<q-select
v-model="item.attrPrivilege"
:options="attrPrivilegeOp"
option-value="id"
option-label="id"
dense
outlined
emit-value
map-options
:disable="
!item.selected ||
(item.selected && item.attrOwnership === 'OWNER')
"
label="สิทธิ์เข้าถึงข้อมูล"
style="min-width: 100px"
:rules="[(val:string) => !!val || `${'กรุณาเลือกสิทธิ์เข้าถึงข้อมูล'}`,]"
>
</q-select
></q-td>
</q-tr>
</template>
</q-table>
</div>
<q-card-actions align="right">
<q-btn label="บันทึก" color="secondary" type="submit"
><q-tooltip>นทกขอม</q-tooltip></q-btn
>
</q-card-actions>
</q-card>
</q-form>
</template>
<style scoped>
.absolute-custom {
position: absolute;
top: -5px;
right: -5px;
}
.absolute-customH {
position: absolute;
top: -2px;
right: -2px;
}
.my-sticky-dynamic {
/* Large screens and up */
height: 65vh;
.q-table__top,
.q-table__bottom,
thead tr:first-child th {
/* bg color is important for th; just specify one */
background-color: #fff; /* Replace with your desired color */
}
thead tr th {
position: sticky;
z-index: 1;
top: 0; /* Default top position for all th elements */
background-color: #fff; /* Replace with your desired color */
}
/* this will be the loading indicator */
thead tr:last-child th {
/* height of all previous header rows */
top: 48px; /* Adjust this value based on the cumulative height of previous header rows */
}
thead tr:first-child th {
top: 0;
}
/* prevent scrolling behind sticky top row on focus */
tbody {
/* height of all previous header rows */
scroll-margin-top: 48px; /* Adjust this value based on the cumulative height of previous header rows */
}
}
</style>