refactor: replace role-based access checks with canAccess utility in menu components
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 7s

This commit is contained in:
puriphatt 2025-07-02 14:58:44 +07:00
parent 57660d7991
commit 8799799214
4 changed files with 131 additions and 111 deletions

View file

@ -7,7 +7,7 @@ import useMyBranch from 'stores/my-branch';
import { getUserId, getRole } from 'src/services/keycloak';
import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n';
import { isRoleInclude } from 'src/stores/utils';
import { canAccess } from 'src/stores/utils';
type Menu = {
label: string;
@ -71,82 +71,41 @@ function initMenu() {
{
label: 'branch',
route: '/branch-management',
hidden: !isRoleInclude([
'system',
'head_of_admin',
'admin',
'branch_manager',
'head_of_accountant',
]),
hidden: !canAccess('branch'),
},
{
label: 'personnel',
route: '/personnel-management',
hidden: !isRoleInclude([
'owner',
'system',
'head_of_admin',
'admin',
'branch_manager',
]),
hidden: !canAccess('personnel'),
},
{
label: 'workflow',
route: '/workflow',
hidden: !isRoleInclude(['system', 'head_of_admin', 'admin']),
hidden: !canAccess('workflow'),
},
{
label: 'property',
route: '/property',
hidden: !isRoleInclude(['system', 'head_of_admin', 'admin']),
hidden: !canAccess('workflow'),
},
{
label: 'productService',
route: '/product-service',
hidden: !isRoleInclude([
'system',
'head_of_admin',
'admin',
'branch_manager',
'head_of_accountant',
'head_of_sale',
'sale',
]),
},
{
label: 'customer',
route: '/customer-management',
hidden: !isRoleInclude([
'system',
'head_of_admin',
'admin',
'branch_manager',
'head_of_accountant',
'accountant',
'head_of_sale',
'sale',
]),
hidden: !canAccess('customer'),
},
{
label: 'agencies',
route: '/agencies-management',
hidden: !isRoleInclude(['system', 'head_of_admin', 'admin']),
},
],
},
{
label: 'menu.sales',
icon: 'mdi-store-settings-outline',
hidden: !isRoleInclude([
'system',
'head_of_admin',
'admin',
'branch_manager',
'head_of_accountant',
'accountant',
'head_of_sale',
'sale',
]),
children: [
{ label: 'quotation', route: '/quotation' },
{ label: 'invoice', route: '/invoice' },
@ -169,16 +128,7 @@ function initMenu() {
label: 'menu.account',
icon: 'mdi-bank-outline',
disabled: false,
hidden: !isRoleInclude([
'system',
'head_of_admin',
'admin',
'branch_manager',
'head_of_accountant',
'accountant',
'head_of_sale',
'sale',
]),
hidden: !canAccess('account'),
children: [
{ label: 'receipt', route: '/receipt' },
{ label: 'creditNote', route: '/credit-note' },
@ -200,10 +150,13 @@ function initMenu() {
{
label: 'menu.overall',
icon: 'mdi-monitor-dashboard',
hidden: !isRoleInclude(['system', 'head_of_admin', 'admin', 'executive']),
children: [
{ label: 'report', route: '/report' },
{ label: 'dashboard', route: '/dash-board' },
{
label: 'dashboard',
route: '/dash-board',
hidden: !canAccess('dashBoard'),
},
],
},

View file

@ -2,17 +2,15 @@
import MenuItem from 'components/00_home/MenuItem.vue';
import { useNavigator } from 'src/stores/navigator';
import { onMounted, ref } from 'vue';
import { getRole } from 'src/services/keycloak';
import { canAccess } from 'src/stores/utils';
const navigatorStore = useNavigator();
const menu = ref<InstanceType<typeof MenuItem>['$props']['list']>([]);
const role = ref();
onMounted(() => {
navigatorStore.current.title = '';
navigatorStore.current.path = [{ text: '' }];
role.value = getRole();
menu.value = [
{
value: 'branch-management',
@ -20,14 +18,7 @@ onMounted(() => {
color: 'green',
title: 'menu.branch',
caption: 'menu.branchCaption',
hidden:
role.value.includes('admin') ||
role.value.includes('branch_admin') ||
role.value.includes('head_of_admin') ||
role.value.includes('system') ||
role.value.includes('owner')
? false
: true,
hidden: !canAccess('branch'),
},
{
value: 'personnel-management',
@ -35,15 +26,7 @@ onMounted(() => {
color: 'cyan',
title: 'menu.user',
caption: 'menu.userCaption',
hidden:
role.value.includes('admin') ||
role.value.includes('branch_admin') ||
role.value.includes('head_of_admin') ||
role.value.includes('system') ||
role.value.includes('owner') ||
role.value.includes('branch_manager')
? false
: true,
hidden: !canAccess('personnel'),
},
{
value: 'customer-management',
@ -52,6 +35,7 @@ onMounted(() => {
title: 'menu.customer',
caption: 'menu.customerCaption',
isax: true,
hidden: !canAccess('customer'),
},
{
value: 'product-service',
@ -115,6 +99,7 @@ onMounted(() => {
title: 'menu.dashboard',
caption: 'menu.dashboardCaption',
isax: true,
hidden: !canAccess('dashBoard'),
},
];
});

View file

@ -1,5 +1,5 @@
import { RouteRecordRaw } from 'vue-router';
import { isRoleInclude } from 'stores/utils';
import { isRoleInclude, canAccess } from 'stores/utils';
const routes: RouteRecordRaw[] = [
{
@ -16,21 +16,8 @@ const routes: RouteRecordRaw[] = [
path: '/branch-management',
name: 'BranchManagement',
beforeEnter: (to, from, next) => {
if (
isRoleInclude([
'admin',
'branch_admin',
'head_of_admin',
'head_of_account',
'system',
'owner',
'branch_manager',
])
) {
next();
} else {
next('/');
}
if (canAccess('branch')) next();
else next('/');
},
component: () => import('pages/01_branch-management/MainPage.vue'),
},
@ -38,36 +25,36 @@ const routes: RouteRecordRaw[] = [
path: '/personnel-management',
name: 'PersonnelManagement',
beforeEnter: (to, from, next) => {
if (
isRoleInclude([
'admin',
'branch_admin',
'head_of_admin',
'system',
'owner',
'branch_manager',
])
) {
next();
} else {
next('/');
}
if (canAccess('personnel')) next();
else next('/');
},
component: () => import('pages/02_personnel-management/MainPage.vue'),
},
{
path: '/customer-management',
name: 'CustomerManagement',
beforeEnter: (to, from, next) => {
if (canAccess('customer')) next();
else next('/');
},
component: () => import('pages/03_customer-management/MainPage.vue'),
},
{
path: '/customer-management/:customerId',
name: 'CustomerSpecificManagement',
beforeEnter: (to, from, next) => {
if (canAccess('customer')) next();
else next('/');
},
component: () => import('pages/03_customer-management/MainPage.vue'),
},
{
path: '/customer-management/:customerId/branch',
name: 'CustomerBranchManagement',
beforeEnter: (to, from, next) => {
if (canAccess('customer')) next();
else next('/');
},
component: () => import('pages/03_customer-management/MainPage.vue'),
},
{
@ -78,11 +65,19 @@ const routes: RouteRecordRaw[] = [
{
path: '/workflow',
name: 'Workflow',
beforeEnter: (to, from, next) => {
if (canAccess('workflow')) next();
else next('/');
},
component: () => import('pages/04_flow-managment/MainPage.vue'),
},
{
path: '/property',
name: 'Property',
beforeEnter: (to, from, next) => {
if (canAccess('workflow')) next();
else next('/');
},
component: () => import('pages/04_property-managment/MainPage.vue'),
},
{
@ -98,6 +93,10 @@ const routes: RouteRecordRaw[] = [
{
path: '/agencies-management',
name: 'agencies-management',
beforeEnter: (to, from, next) => {
if (canAccess('agencies')) next();
else next('/');
},
component: () => import('pages/07_agencies-management/MainPage.vue'),
},
{
@ -138,6 +137,10 @@ const routes: RouteRecordRaw[] = [
{
path: '/dash-board',
name: 'dashBoard',
beforeEnter: (to, from, next) => {
if (canAccess('dashBoard')) next();
else next('/');
},
component: () => import('pages/15_dash-board/MainPage.vue'),
},
{
@ -225,7 +228,7 @@ const routes: RouteRecordRaw[] = [
},
{
path: '/receipt/:id',
name: 'receiptform',
name: 'receiptForm',
component: () => import('pages/13_receipt/MainPage.vue'),
},
{

View file

@ -221,11 +221,90 @@ export function checkTabBeforeAdd(data: unknown[], except?: string[]) {
export function isRoleInclude(role2check: string[]): boolean {
const roles = getRole() ?? [];
const isIncluded = role2check.some((r) => roles.includes(r));
const filterRole = roles.filter(
(role: string) =>
role !== 'offline_access' &&
role !== 'uma_authorization' &&
!role.startsWith('default-roles'),
);
const isIncluded = role2check.some((r) => filterRole.includes(r));
return isIncluded;
}
export function canAccess(
menu: string,
action: 'edit' | 'view' = 'view',
): boolean {
// uma_authorization = all roles
const allRoles = [
'head_of_admin',
'admin',
'executive',
'accountant',
'branch_admin',
'branch_manager',
'branch_accountant',
'head_of_sale',
'sale',
'data_entry',
'document_checker',
'messenger',
'corporate_customer',
'agency',
];
const permissions = {
branch: {
edit: allRoles.slice(0, 7),
view: allRoles.slice(0, 7),
},
personnel: {
edit: allRoles.slice(0, 6).filter((r) => r !== 'accountant'),
view: allRoles.slice(0, 6).filter((r) => r !== 'accountant'),
},
product: {
edit: allRoles.slice(0, 7),
view: allRoles,
},
workflow: {
edit: allRoles.slice(0, 6),
view: allRoles.filter((r) => r !== 'branch_accountant'),
},
customer: {
edit: allRoles.slice(0, 6),
view: allRoles.slice(0, 8),
},
agencies: {
edit: allRoles.slice(0, 7),
view: allRoles,
},
related: {
// ใช้กับหลายเมนู
edit: allRoles.slice(0, 6),
view: allRoles,
},
account: {
edit: allRoles.slice(0, 6),
view: allRoles.slice(0, 7),
},
uploadSlip: {
edit: allRoles.slice(0, 6),
view: allRoles.filter((r) => r !== 'head_of_sale' && r !== 'sale'),
},
dashBoard: {
edit: allRoles.slice(0, 6).filter((r) => r !== 'admin'),
view: allRoles.filter((r) => r !== 'admin'),
},
};
const roles = getRole() ?? [];
if (roles.includes('system')) return true;
const allowedRoles = permissions[menu]?.[action] || [];
return allowedRoles.some((role: string) => roles.includes(role));
}
export function resetScrollBar(elementId: string) {
const element = document.getElementById(elementId);