[FEAT] 優化帳號管理授權顯示邏輯與 UI 樣式一致性
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 59s

This commit is contained in:
2026-03-23 17:16:26 +08:00
parent 72812f9b0b
commit 38770b080b
26 changed files with 1265 additions and 444 deletions

View File

@@ -3,6 +3,16 @@
@section('content')
<div class="space-y-6" x-data="{
selectedPermissions: {{ json_encode($role->permissions->pluck('name')->toArray()) }},
@php
$availablePermissions = $all_permissions->flatten();
if (!$role->is_system) {
$availablePermissions = $availablePermissions->filter(function($p) {
return !str_starts_with($p->name, 'menu.basic') &&
!str_starts_with($p->name, 'menu.permissions');
});
}
@endphp
availableCount: {{ $availablePermissions->count() }},
activeCategory: '',
toggleCategory(category, permissions) {
const allSelected = permissions.every(p => this.selectedPermissions.includes(p));
@@ -20,6 +30,32 @@
const selectedCount = permissions.filter(p => this.selectedPermissions.includes(p)).length;
return selectedCount > 0 && selectedCount < permissions.length;
},
toggleParent(parentName, childrenNames) {
const isSelected = this.selectedPermissions.includes(parentName);
if (isSelected) {
// 取消父項目與所有子項目
this.selectedPermissions = this.selectedPermissions.filter(p => p !== parentName && !childrenNames.includes(p));
} else {
// 勾選父項目
if (!this.selectedPermissions.includes(parentName)) {
this.selectedPermissions.push(parentName);
}
// 勾選所有尚未勾選的子項目
childrenNames.forEach(p => {
if (!this.selectedPermissions.includes(p)) this.selectedPermissions.push(p);
});
}
},
isParentSelected(parentName, childrenNames) {
return this.selectedPermissions.includes(parentName) &&
childrenNames.every(p => this.selectedPermissions.includes(p));
},
isParentPartial(parentName, childrenNames) {
const hasParent = this.selectedPermissions.includes(parentName);
const selectedChildrenCount = childrenNames.filter(p => this.selectedPermissions.includes(p)).length;
return (hasParent && selectedChildrenCount < childrenNames.length) ||
(!hasParent && selectedChildrenCount > 0);
},
scrollTo(id) {
const el = document.getElementById(id);
if (el) {
@@ -140,7 +176,7 @@
<span class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-1">{{ __('Total Selected') }}</span>
<div class="flex items-baseline gap-1">
<span class="text-3xl font-display font-black text-cyan-500" x-text="selectedPermissions.length">0</span>
<span class="text-xs font-bold text-slate-400">/ {{ $all_permissions->flatten()->count() }}</span>
<span class="text-xs font-bold text-slate-400">/ <span x-text="availableCount"></span></span>
</div>
</div>
<div class="w-12 h-12 rounded-2xl bg-emerald-500/5 flex items-center justify-center text-emerald-500">
@@ -156,6 +192,13 @@
<div class="flex-1 w-full space-y-12">
@foreach($all_permissions as $group => $permissions)
@php
// 如果非系統角色,過濾掉敏感權限
if (!$role->is_system && $group === 'menu') {
$permissions = $permissions->filter(function($p) {
return !str_starts_with($p->name, 'menu.basic') &&
!str_starts_with($p->name, 'menu.permissions');
});
}
$groupId = 'group-' . $group;
$groupPermissions = $permissions->pluck('name')->toArray();
@endphp
@@ -218,9 +261,11 @@
<div class="flex items-center pr-1">
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" name="permissions[]" value="{{ $parent->name }}"
x-model="selectedPermissions"
:checked="selectedPermissions.includes('{{ $parent->name }}')"
@change="toggleParent('{{ $parent->name }}', {{ json_encode($children->pluck('name')->toArray()) }})"
class="sr-only peer">
<div class="w-11 h-6 bg-slate-200 dark:bg-slate-700 rounded-full peer peer-focus:outline-none peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-cyan-500 transition-all duration-200 shadow-inner"></div>
<div class="w-11 h-6 bg-slate-200 dark:bg-slate-700 rounded-full peer peer-focus:outline-none peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-cyan-500 transition-all duration-200 shadow-inner"
:class="isParentPartial('{{ $parent->name }}', {{ json_encode($children->pluck('name')->toArray()) }}) ? 'ring-2 ring-cyan-500/50' : ''"></div>
</label>
</div>
</div>
@@ -237,9 +282,9 @@
<div class="relative flex items-center flex-shrink-0">
<input type="checkbox"
name="permissions[]"
value="{{ $child->id }}"
class="w-4 h-4 rounded border-2 border-slate-300 dark:border-slate-700 text-cyan-500 focus:ring-cyan-500/20 transition-all cursor-pointer accent-cyan-500"
{{ $role->hasPermissionTo($child->name) ? 'checked' : '' }}>
value="{{ $child->name }}"
x-model="selectedPermissions"
class="w-4 h-4 rounded border-2 border-slate-300 dark:border-slate-700 text-cyan-500 focus:ring-cyan-500/20 transition-all cursor-pointer accent-cyan-500">
</div>
</label>
@endforeach