Page Phân quyền
This commit is contained in:
32
components/menu/MenuGroupCheck.vue
Normal file
32
components/menu/MenuGroupCheck.vue
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mx-2">
|
||||||
|
<a class="ml-5" @click="userRights">
|
||||||
|
<SvgIcon v-bind="{ name: 'list.svg', type: 'gray', size: 20 }"></SvgIcon>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
const { $store } = useNuxtApp();
|
||||||
|
const emit = defineEmits(["clickevent"]);
|
||||||
|
var props = defineProps({
|
||||||
|
appid: Number,
|
||||||
|
row: Object,
|
||||||
|
api: String,
|
||||||
|
setting: String,
|
||||||
|
});
|
||||||
|
|
||||||
|
function userRights() {
|
||||||
|
emit("clickevent", {
|
||||||
|
name: "dataevent",
|
||||||
|
data: {
|
||||||
|
modal: {
|
||||||
|
title: $store.lang === "en" ? "Group rights" : "Phân quyền theo nhóm",
|
||||||
|
height: "500px",
|
||||||
|
width: "500px",
|
||||||
|
component: "menu/MenuGroupRights",
|
||||||
|
vbind: { row: props.row, api: props.api, setting: props.setting },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
190
components/menu/MenuGroupRights.vue
Normal file
190
components/menu/MenuGroupRights.vue
Normal 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>
|
||||||
@@ -131,7 +131,9 @@ export default defineNuxtPlugin(() => {
|
|||||||
values:
|
values:
|
||||||
"id,customer,customer__code,status,status__name,branch__code,country__code,currency__code,loan_amount,loan_term,code,fullname,phone,province,district,address,legal_type,legal_type__code,sex,sex__name,issue_place,loan_term,loan_amount,legal_type__name,legal_code,issue_date,issue_place,country,collaborator,create_time,update_time",
|
"id,customer,customer__code,status,status__name,branch__code,country__code,currency__code,loan_amount,loan_term,code,fullname,phone,province,district,address,legal_type,legal_type__code,sex,sex__name,issue_place,loan_term,loan_amount,legal_type__name,legal_code,issue_date,issue_place,country,collaborator,create_time,update_time",
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
{name: 'grouprights', url: 'data/Group_Rights/', url_detail: 'data-detail/Group_Rights/', params: {sort: '-id'}},
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import MenuUser from '~/components/menu/MenuUser.vue'
|
|||||||
import MenuCV from '~/components/menu/MenuCV.vue'
|
import MenuCV from '~/components/menu/MenuCV.vue'
|
||||||
import MenuStaff from '~/components/menu/MenuStaff.vue'
|
import MenuStaff from '~/components/menu/MenuStaff.vue'
|
||||||
import Configuration from '~/components/maintab/Configuration.vue'
|
import Configuration from '~/components/maintab/Configuration.vue'
|
||||||
|
import MenuGroupCheck from '~/components/menu/MenuGroupCheck.vue'
|
||||||
|
|
||||||
// import DataDeletion from '~/components/maintab/DataDeletion.vue'
|
// import DataDeletion from '~/components/maintab/DataDeletion.vue'
|
||||||
// import MarkData from '~/components/menu/MarkData.vue'
|
// import MarkData from '~/components/menu/MarkData.vue'
|
||||||
@@ -33,7 +34,7 @@ import Configuration from '~/components/maintab/Configuration.vue'
|
|||||||
|
|
||||||
const components = {Notebox, MenuAction, Datepicker, PickDay, ImageGallery, FileGallery, FileUpload, ChipImage, Avatarbox,
|
const components = {Notebox, MenuAction, Datepicker, PickDay, ImageGallery, FileGallery, FileUpload, ChipImage, Avatarbox,
|
||||||
DataTable, Imagebox, Editor, InputPhone, InputEmail, InputNumber, DataView, FormatNumber, SvgIcon, MenuAdd, Configuration,
|
DataTable, Imagebox, Editor, InputPhone, InputEmail, InputNumber, DataView, FormatNumber, SvgIcon, MenuAdd, Configuration,
|
||||||
MenuCheck, MenuCollab, MenuPhone, FormatDate, MenuUser, MenuCV, MenuStaff, MenuCheck}
|
MenuCheck, MenuCollab, MenuPhone, FormatDate, MenuUser, MenuCV, MenuStaff, MenuCheck, MenuGroupCheck}
|
||||||
|
|
||||||
export default defineNuxtPlugin((nuxtApp) => {
|
export default defineNuxtPlugin((nuxtApp) => {
|
||||||
Object.entries(components).forEach(([name, component]) => {
|
Object.entries(components).forEach(([name, component]) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user