corrad-af-2024/pages/roles/templates.vue
Afiq f05dd42c16 Enhance README and implement RBAC system with Authentik integration
- Updated README.md to reflect the new project name and provide an overview of the Role-Based Access Control (RBAC) system.
- Added new components for RBAC management, including:
  - PermissionExample.vue: Demonstrates permission-based navigation.
  - GroupCard.vue: Displays group information and assigned roles.
  - PermissionMatrix.vue: Visual representation of permissions across roles and resources.
  - RoleTemplates.vue: Quick role templates for applying pre-configured permissions.
  - StatsCards.vue: Displays statistics related to users, groups, and roles.
- Introduced useRbacPermissions.js for managing permission checks.
- Created docker-compose.yml for PostgreSQL and Redis services.
- Developed comprehensive documentation for application management and Authentik integration.
- Added multiple pages for managing applications, groups, roles, and users, including bulk operations and templates.
- Updated navigation structure to include new RBAC management paths.
2025-05-31 15:58:41 +08:00

278 lines
9.2 KiB
Vue

<script setup>
definePageMeta({
title: "Role Templates",
middleware: ["auth"],
requiresAuth: true,
breadcrumb: [
{ name: "Dashboard", path: "/dashboard" },
{ name: "Roles", path: "/roles" },
{ name: "Templates", path: "/roles/templates", type: "current" }
]
});
import { ref, reactive } from 'vue'
// Template state management
const templates = ref([
{
id: '1',
name: 'Administrator',
description: 'Full system access with all permissions',
permissions: {
menus: ['*'],
components: ['*'],
features: ['*']
}
},
{
id: '2',
name: 'Manager',
description: 'Department management with limited admin access',
permissions: {
menus: ['dashboard', 'users', 'reports'],
components: ['user.view', 'user.edit', 'reports.view'],
features: ['export.data', 'approve.requests']
}
},
{
id: '3',
name: 'Editor',
description: 'Content management with no admin access',
permissions: {
menus: ['dashboard', 'content'],
components: ['content.view', 'content.edit'],
features: ['export.data']
}
}
])
// Form state
const templateForm = reactive({
name: '',
description: '',
permissions: {
menus: [],
components: [],
features: []
}
})
// Available resources (in real app, this would be fetched from API)
const availableResources = reactive({
menus: [
{ id: 'dashboard', name: 'Dashboard', key: 'menu.dashboard' },
{ id: 'users', name: 'Users', key: 'menu.users' },
{ id: 'reports', name: 'Reports', key: 'menu.reports' },
{ id: 'content', name: 'Content', key: 'menu.content' }
],
components: [
{ id: 'user.view', name: 'View User', key: 'component.user.view' },
{ id: 'user.edit', name: 'Edit User', key: 'component.user.edit' },
{ id: 'content.view', name: 'View Content', key: 'component.content.view' },
{ id: 'content.edit', name: 'Edit Content', key: 'component.content.edit' },
{ id: 'reports.view', name: 'View Reports', key: 'component.reports.view' }
],
features: [
{ id: 'export.data', name: 'Export Data', key: 'feature.export.data' },
{ id: 'approve.requests', name: 'Approve Requests', key: 'feature.approve.requests' }
]
})
// Form handlers
const handleTemplateSubmit = (data) => {
const newTemplate = {
id: Date.now().toString(),
...data,
permissions: {
menus: data.permissions.menus || [],
components: data.permissions.components || [],
features: data.permissions.features || []
}
}
templates.value.push(newTemplate)
// Reset form
templateForm.name = ''
templateForm.description = ''
templateForm.permissions = {
menus: [],
components: [],
features: []
}
}
// Delete handler
const deleteTemplate = (id) => {
templates.value = templates.value.filter(template => template.id !== id)
}
// Clone handler
const cloneTemplate = (template) => {
const clonedTemplate = {
...template,
id: Date.now().toString(),
name: `${template.name} (Copy)`,
}
templates.value.push(clonedTemplate)
}
// Helper to format permission list
const formatPermissionList = (permissions) => {
if (permissions.includes('*')) return 'All permissions'
return permissions.length + ' permissions'
}
</script>
<template>
<div>
<LayoutsBreadcrumb />
<!-- Header -->
<rs-card class="mb-6">
<template #body>
<div class="flex flex-col lg:flex-row lg:items-center lg:justify-between">
<div class="mb-4 lg:mb-0">
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">Role Templates</h1>
<p class="text-gray-600 dark:text-gray-400">Manage predefined role templates with preset permissions</p>
</div>
</div>
</template>
</rs-card>
<!-- Content -->
<div class="space-y-6">
<!-- Add Template Form -->
<rs-card>
<template #header>
<h3 class="text-lg font-medium text-gray-900 dark:text-white">Create New Template</h3>
</template>
<template #body>
<FormKit
type="form"
:config="{ validationVisibility: 'submit' }"
@submit="handleTemplateSubmit"
:value="templateForm"
:actions="false"
>
<div class="space-y-6">
<!-- Basic Info -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<FormKit
type="text"
name="name"
label="Template Name"
validation="required"
placeholder="e.g., Department Manager"
/>
<FormKit
type="textarea"
name="description"
label="Description"
validation="required"
placeholder="Describe the role and its permissions"
/>
</div>
<!-- Permissions -->
<div class="space-y-6">
<h4 class="text-lg font-medium text-gray-900 dark:text-white">Permissions</h4>
<!-- Menu Permissions -->
<div>
<FormKit
type="checkbox"
name="permissions.menus"
label="Menu Access"
:options="availableResources.menus.reduce((acc, menu) => {
acc[menu.id] = menu.name
return acc
}, {'*': 'All Menus'})"
/>
</div>
<!-- Component Permissions -->
<div>
<FormKit
type="checkbox"
name="permissions.components"
label="Component Access"
:options="availableResources.components.reduce((acc, component) => {
acc[component.id] = component.name
return acc
}, {'*': 'All Components'})"
/>
</div>
<!-- Feature Permissions -->
<div>
<FormKit
type="checkbox"
name="permissions.features"
label="Feature Access"
:options="availableResources.features.reduce((acc, feature) => {
acc[feature.id] = feature.name
return acc
}, {'*': 'All Features'})"
/>
</div>
</div>
<div class="flex justify-end">
<rs-button type="submit" variant="primary">
<Icon name="ph:plus" class="w-4 h-4 mr-2" />
Create Template
</rs-button>
</div>
</div>
</FormKit>
</template>
</rs-card>
<!-- Template List -->
<rs-card>
<template #header>
<div class="flex items-center justify-between">
<h3 class="text-lg font-medium text-gray-900 dark:text-white">Available Templates</h3>
<rs-badge variant="secondary">{{ templates.length }} templates</rs-badge>
</div>
</template>
<template #body>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div v-for="template in templates" :key="template.id" class="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-6">
<div class="flex justify-between items-start mb-4">
<div>
<h4 class="text-lg font-medium text-gray-900 dark:text-white">{{ template.name }}</h4>
<p class="text-sm text-gray-600 dark:text-gray-400">{{ template.description }}</p>
</div>
<div class="flex space-x-2">
<rs-button @click="cloneTemplate(template)" variant="secondary-outline" size="sm">
<Icon name="ph:copy" class="w-4 h-4" />
</rs-button>
<rs-button @click="deleteTemplate(template.id)" variant="danger-outline" size="sm">
<Icon name="ph:trash" class="w-4 h-4" />
</rs-button>
</div>
</div>
<div class="space-y-3">
<div class="flex items-center text-sm">
<Icon name="ph:list" class="w-4 h-4 mr-2 text-blue-600" />
<span class="text-gray-700 dark:text-gray-300">{{ formatPermissionList(template.permissions.menus) }}</span>
</div>
<div class="flex items-center text-sm">
<Icon name="ph:squares-four" class="w-4 h-4 mr-2 text-green-600" />
<span class="text-gray-700 dark:text-gray-300">{{ formatPermissionList(template.permissions.components) }}</span>
</div>
<div class="flex items-center text-sm">
<Icon name="ph:gear" class="w-4 h-4 mr-2 text-purple-600" />
<span class="text-gray-700 dark:text-gray-300">{{ formatPermissionList(template.permissions.features) }}</span>
</div>
</div>
</div>
</div>
</template>
</rs-card>
</div>
</div>
</template>