This commit is contained in:
2026-08-04 10:31:53 +08:00
parent 198101c42c
commit 5c25806081
10 changed files with 100 additions and 31 deletions
@@ -4,7 +4,7 @@ import { useRoute } from 'vue-router'
import { ElMessage } from 'element-plus'
import { LockKeyhole, RotateCcw, Save, ShieldCheck } from '@lucide/vue'
import { useTenantAdministrationStore } from '@/modules/tenant-management/store/tenantAdministration'
import { TENANT_PERMISSION_GROUPS } from '@/modules/tenant-management/contracts'
import { REQUIRED_TENANT_PERMISSION_CODES, TENANT_PERMISSION_GROUPS } from '@/modules/tenant-management/contracts'
import { useAuthStore } from '@/modules/auth/public'
const store = useTenantAdministrationStore()
@@ -21,6 +21,11 @@ const saving = ref(false)
const selectedRole = computed(() => store.roles.find((role) => role.id === selectedRoleId.value))
const editable = computed(() => Boolean(auth.hasPermission('company:permission:assign') && selectedRole.value && !selectedRole.value.builtin && selectedRole.value.status === 'ACTIVE'))
const hasChanges = computed(() => [...selectedCodes.value].sort().join('|') !== [...savedCodes.value].sort().join('|'))
const requiredPermissionCodes = new Set<string>(REQUIRED_TENANT_PERMISSION_CODES)
function isRequiredPermission(code: string) {
return requiredPermissionCodes.has(code)
}
function loadRolePermissions() {
const codes = selectedRole.value?.permissionCodes ?? []
@@ -64,7 +69,7 @@ function groupIndeterminate(groupKey: string) {
function toggleGroup(groupKey: string, checked: boolean) {
const codes = groupCodes(groupKey)
if (checked) selectedCodes.value = [...new Set([...selectedCodes.value, ...codes])]
else selectedCodes.value = selectedCodes.value.filter((code) => !codes.includes(code))
else selectedCodes.value = selectedCodes.value.filter((code) => !codes.includes(code) || isRequiredPermission(code))
}
function resetPermissions() {
@@ -73,8 +78,6 @@ function resetPermissions() {
async function savePermissions() {
if (!selectedRole.value || !editable.value || saving.value) return
if (!selectedCodes.value.includes('account:profile:view')) selectedCodes.value.unshift('account:profile:view')
if (!selectedCodes.value.includes('dashboard:view')) selectedCodes.value.unshift('dashboard:view')
saving.value = true
try {
await store.setRolePermissions(selectedRole.value.id, selectedCodes.value)
@@ -113,11 +116,11 @@ async function savePermissions() {
<div class="permission-groups">
<article v-for="group in TENANT_PERMISSION_GROUPS" :key="group.key" class="client-card permission-group" :class="{ 'permission-group--single': group.items.length === 1 }">
<header>
<el-checkbox :model-value="groupChecked(group.key)" :indeterminate="groupIndeterminate(group.key)" :disabled="!editable" @change="toggleGroup(group.key, Boolean($event))"><strong>{{ group.label }}</strong></el-checkbox>
<el-checkbox :model-value="groupChecked(group.key)" :indeterminate="groupIndeterminate(group.key)" :disabled="!editable || group.items.every((item) => isRequiredPermission(item.code))" @change="toggleGroup(group.key, Boolean($event))"><strong>{{ group.label }}</strong></el-checkbox>
<span>{{ group.items.filter((item) => selectedCodes.includes(item.code)).length }} / {{ group.items.length }}</span>
</header>
<el-checkbox-group v-model="selectedCodes" :disabled="!editable">
<el-checkbox v-for="item in group.items" :key="item.code" :value="item.code" class="permission-item" :class="{ selected: selectedCodes.includes(item.code) }">
<el-checkbox v-for="item in group.items" :key="item.code" :value="item.code" :disabled="isRequiredPermission(item.code)" class="permission-item" :class="{ selected: selectedCodes.includes(item.code) }">
<span class="permission-copy"><strong>{{ item.label }}</strong><small>{{ item.description }}</small><code>{{ item.code }}</code></span>
</el-checkbox>
</el-checkbox-group>