EDMS/pages/dms/access-management.vue
2025-06-05 14:57:08 +08:00

206 lines
7.0 KiB
Vue

<script setup>
import { ref, computed, onMounted, defineAsyncComponent } from 'vue';
import { useDmsStore } from '~/stores/dms';
// Define page metadata
definePageMeta({
title: "Access Management",
middleware: ["auth"],
requiresAuth: true,
breadcrumb: [
{
name: "DMS",
path: "/dms",
},
{
name: "Access Management",
path: "/dms/access-management",
},
],
});
// Lazy load components to improve initial page load
const DMSApprovalQueue = defineAsyncComponent(() =>
import('~/components/dms/workflows/DMSApprovalQueue.vue')
);
const DMSAccessRequestTracker = defineAsyncComponent(() =>
import('~/components/dms/workflows/DMSAccessRequestTracker.vue')
);
// Store
const dmsStore = useDmsStore();
// Component state
const activeTab = ref('requests');
const isLoading = ref(true);
const hasError = ref(false);
const errorMessage = ref('');
// User role and permissions
const userPermissions = ref({
canApprove: false,
canReject: false,
canViewAll: false
});
// Tabs definition
const tabs = [
{
id: 'requests',
label: 'Access Requests',
icon: 'lock-access',
description: 'Manage pending and historical access requests'
},
{
id: 'metrics',
label: 'Performance Metrics',
icon: 'chart',
description: 'Track access request KPIs and time metrics'
}
];
// Methods
const changeTab = (tabId) => {
activeTab.value = tabId;
};
// Load user permissions
const loadUserPermissions = async () => {
try {
isLoading.value = true;
// In a real implementation, this would be fetched from an authentication service
// For now we'll simulate it with the store
const userId = dmsStore.currentUser.id;
const userRole = dmsStore.currentUser.role;
// Get permissions from the store (simulated Authentik integration)
const permissions = await dmsStore.getRbacPermissions(userId);
// Set the permissions
userPermissions.value = {
canApprove: permissions.permissions.accessRequests.approve || false,
canReject: permissions.permissions.accessRequests.reject || false,
canViewAll: permissions.permissions.accessRequests.viewAll || false
};
} catch (error) {
console.error('Failed to load user permissions:', error);
hasError.value = true;
errorMessage.value = 'Failed to load user permissions. Please try again.';
} finally {
isLoading.value = false;
}
};
// Get SVG icon
const getSvgIcon = (iconName) => {
const icons = {
'lock-access': `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>`,
'chart': `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"></line><line x1="12" y1="20" x2="12" y2="4"></line><line x1="6" y1="20" x2="6" y2="14"></line></svg>`,
'user': `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>`
};
return icons[iconName] || '';
};
// Lifecycle hooks
onMounted(() => {
loadUserPermissions();
});
</script>
<template>
<div class="dms-access-management h-screen flex flex-col">
<LayoutsBreadcrumb />
<div class="flex-1 min-h-0 p-4">
<RsCard
height="full"
overflow="hidden"
bodyPadding="none"
class="h-full"
>
<template #header>
<div class="flex justify-between items-center">
<h1 class="text-2xl font-bold text-gray-900 dark:text-gray-100">Access Management</h1>
<div class="flex space-x-2">
<RsButton variant="secondary-outline" size="sm">
<Icon name="mdi:export" class="w-4 h-4 mr-2" />
Export Report
</RsButton>
<RsButton variant="primary" size="sm">
<Icon name="mdi:plus" class="w-4 h-4 mr-2" />
New Request
</RsButton>
</div>
</div>
</template>
<template #body>
<div class="h-full flex flex-col min-h-0">
<!-- Tabs -->
<div class="border-b border-gray-200 dark:border-gray-700 px-6">
<nav class="-mb-px flex space-x-8">
<button
@click="activeTab = 'requests'"
:class="[
'py-2 px-1 border-b-2 font-medium text-sm transition-colors',
activeTab === 'requests'
? 'border-primary text-primary'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300'
]"
>
Access Requests
<span v-if="pendingCount > 0" class="ml-2 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">
{{ pendingCount }}
</span>
</button>
<button
@click="activeTab = 'metrics'"
:class="[
'py-2 px-1 border-b-2 font-medium text-sm transition-colors',
activeTab === 'metrics'
? 'border-primary text-primary'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300'
]"
>
Performance Metrics
</button>
</nav>
</div>
<!-- Tab Content - Scrollable -->
<div class="flex-1 overflow-auto min-h-0">
<!-- Access Requests Tab -->
<div v-if="activeTab === 'requests'" class="h-full">
<DMSApprovalQueue
:showClosed="userPermissions.canViewAll"
:filterByUser="userPermissions.canViewAll ? null : dmsStore.currentUser.id"
:maxItems="0"
/>
</div>
<!-- Metrics Tab -->
<div v-else-if="activeTab === 'metrics'" class="h-full">
<DMSAccessRequestTracker
:userId="userPermissions.canViewAll ? null : dmsStore.currentUser.id"
:timeRange="'30days'"
:showPersonal="true"
:showDepartmental="userPermissions.canViewAll"
/>
</div>
</div>
</div>
</template>
</RsCard>
</div>
</div>
</template>
<style scoped>
.dms-access-management {
height: calc(100vh - 64px);
}
</style>