Page Phân quyền

This commit is contained in:
Thien Pham Van
2026-01-12 14:33:22 +07:00
parent aababfa9c0
commit 618d114c25
4 changed files with 227 additions and 2 deletions

View File

@@ -0,0 +1,190 @@
<template>
<div class="has-text-black">
<div>{{ row.code }} / {{ isVietnamese ? row.name : row.en }} {{ $lang("access-right") }}:</div>
<div class="mt-2">
<span class="icon-text mr-6" v-for="v in options">
<a @click="changeOption(v)">
<SvgIcon
v-bind="{
name: option === v.code ? 'radio-checked.svg' : 'radio-unchecked.svg',
type: option === v.code ? 'blue' : 'gray',
size: 25,
}"
/>
</a>
<b class="fs-18">{{ v[$store.lang === "en" ? "en" : "name"] }}</b>
</span>
</div>
<aside class="menu">
<ul class="menu-list" v-for="v in topmenu">
<li>
<div class="field is-grouped has-background-light has-text-black py-2 px-3">
<div class="control is-expanded">
<b>{{ v[$store.lang] }}</b>
</div>
<div class="control" v-if="v.submenu.length === 0 && option === 'limit'">
<span class="ml-6 is-clickable" @click="changeTick(v)">
<SvgIcon
v-bind="{
name: v.checked ? 'checked.svg' : 'uncheck.svg',
type: v.checked ? 'blue' : 'gray',
size: 25,
}"
></SvgIcon>
</span>
</div>
</div>
<ul>
<li class="border-bottom" v-for="x in v.submenu">
<div class="field is-grouped py-1">
<div class="control is-expanded">
<span class="icon-text">
<span>{{ x[$store.lang] }}</span>
</span>
</div>
<div class="control" v-if="option === 'limit'">
<span class="ml-6 is-clickable" @click="changeTick(x, v)">
<SvgIcon
v-bind="{
name: x.checked ? 'checked.svg' : 'uncheck.svg',
type: x.checked ? 'blue' : 'gray',
size: 25,
}"
></SvgIcon>
</span>
</div>
</div>
</li>
</ul>
</li>
</ul>
</aside>
</div>
</template>
<script setup>
const { $getdata, $filter, $find, $insertapi, $deleteapi, $store } = useNuxtApp();
const props = defineProps({
row: Object,
api: String,
setting: String,
});
const isVietnamese = computed(() => $store.lang.toLowerCase() === "vi");
const options = [
{ code: "all", name: "Tất cả tính năng", en: "All functions" },
{ code: "limit", name: "Bị giới hạn", en: "Limited functions" },
];
const option = ref("limit");
const topmenu = ref([]);
let loanRights = [];
const rows = await $getdata(props.setting, {
category__in: ["topmenu", "submenu"],
});
async function getRights(first) {
loanRights = await $getdata(props.api, { group: props.row.id });
if (loanRights.length === 0 && first) {
option.value = "all";
}
const rights = $filter(rows, { category: "topmenu" });
rights.forEach((parent) => {
const subs = $filter(rows, {
category: "submenu",
classify: parent.code,
});
subs.forEach((sub) => {
const found = $find(loanRights, { setting: sub.id });
sub.checked = !!found;
sub.rightId = found?.id || null;
});
const foundParent = $find(loanRights, { setting: parent.id });
parent.rightId = foundParent?.id || null;
parent.checked = subs.length ? subs.some((s) => s.checked) : !!foundParent;
parent.submenu = subs;
});
topmenu.value = [...rights];
}
async function changeTick(x, v) {
// ===== UNCHECK =====
if (x.checked) {
x.checked = false;
const deleteId = x.rightId;
x.rightId = null;
// Nếu là submenu → kiểm tra parent
if (v) {
const stillChecked = v.submenu.some((s) => s.checked);
if (!stillChecked) {
const parentDelete = v.rightId;
v.checked = false;
v.rightId = null;
if (parentDelete) {
await $deleteapi(props.api, parentDelete);
}
}
}
if (deleteId) {
await $deleteapi(props.api, deleteId);
}
}
// ===== CHECK =====
else {
x.checked = true;
const obj = await $insertapi(props.api, { setting: x.id, group: props.row.id }, undefined, false);
if (obj) x.rightId = obj.id;
if (v && !v.checked) {
v.checked = true;
const parentObj = await $insertapi(props.api, { setting: v.id, group: props.row.id }, undefined, false);
if (parentObj) v.rightId = parentObj.id;
}
}
topmenu.value = [...topmenu.value];
}
async function changeOption(v) {
option.value = v.code;
loanRights = await $getdata(props.api, { group: props.row.id });
if (v.code === "all") {
if (loanRights?.length > 0) {
await Promise.all(loanRights.map((item) => $deleteapi(props.api, item.id)));
}
topmenu.value.forEach((p) => {
p.checked = false;
p.rightId = null;
p.submenu?.forEach((s) => {
s.checked = false;
s.rightId = null;
});
});
topmenu.value = [...topmenu.value];
} else {
await getRights();
}
}
await getRights(true);
</script>