feat: 권한 관리 시스템에 Guard 선택 기능 추가
- 부서 권한 아키텍처 재설계 (Role → Department 직접 할당) - Guard 선택 기능 구현 (API/Web 분리) - 초기화(Reset) 기능 추가 (view 권한만 허용) - UI 개선 (Guard 선택기 + 구분선) 부서 권한 관리: - Department 모델에 HasPermissions trait 추가 - DepartmentPermissionService 완전 재작성 (직접 할당 패턴) - model_has_permissions 테이블 직접 사용 - guard_name 파라미터 모든 메서드에 추가 역할 권한 관리: - RolePermissionService에 guard_name 파라미터 추가 - RolePermissionController에 guard_name 처리 구현 - Guard별 독립적인 권한 매트릭스 관리 UI 개선: - Guard 선택 드롭다운 (Web/API) 추가 - 모든 HTMX 요청에 guard_name 포함 - Guard 변경 시 자동 새로고침 기능 - 시각적 구분선으로 UI 가독성 향상
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
<h1 class="text-2xl font-bold text-gray-800">부서 권한 관리</h1>
|
||||
</div>
|
||||
|
||||
<!-- 부서 선택 버튼 -->
|
||||
<!-- 부서 선택 -->
|
||||
<div class="bg-white rounded-lg shadow-sm mb-6">
|
||||
<div class="px-6 py-4">
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
@@ -22,6 +22,7 @@ class="department-button px-4 py-2 text-sm font-medium rounded-lg border transit
|
||||
data-department-name="{{ $department->name }}"
|
||||
hx-get="/api/admin/department-permissions/matrix"
|
||||
hx-target="#permission-matrix"
|
||||
hx-include="[name='guard_name']"
|
||||
hx-vals='{"department_id": {{ $department->id }}}'
|
||||
onclick="selectDepartment(this)"
|
||||
>
|
||||
@@ -39,12 +40,28 @@ class="department-button px-4 py-2 text-sm font-medium rounded-lg border transit
|
||||
<span class="text-sm font-medium text-gray-700" id="selected-department-name">선택된 부서</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="hidden" name="department_id" id="departmentIdInput" value="">
|
||||
|
||||
<!-- Guard 선택 -->
|
||||
<span class="text-sm font-medium text-gray-700">Guard:</span>
|
||||
<select
|
||||
id="guardNameSelect"
|
||||
name="guard_name"
|
||||
class="px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-primary focus:border-primary"
|
||||
onchange="reloadPermissions()"
|
||||
>
|
||||
<option value="api" selected>API</option>
|
||||
<option value="web">Web</option>
|
||||
</select>
|
||||
|
||||
<!-- 구분선 -->
|
||||
<div class="h-8 w-px bg-gray-300 mx-1"></div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="px-4 py-2 bg-green-600 text-white text-sm font-medium rounded-lg hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500"
|
||||
hx-post="/api/admin/department-permissions/allow-all"
|
||||
hx-target="#permission-matrix"
|
||||
hx-include="[name='department_id']"
|
||||
hx-include="[name='department_id'],[name='guard_name']"
|
||||
>
|
||||
전체 허용
|
||||
</button>
|
||||
@@ -53,16 +70,17 @@ class="px-4 py-2 bg-green-600 text-white text-sm font-medium rounded-lg hover:bg
|
||||
class="px-4 py-2 bg-red-600 text-white text-sm font-medium rounded-lg hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500"
|
||||
hx-post="/api/admin/department-permissions/deny-all"
|
||||
hx-target="#permission-matrix"
|
||||
hx-include="[name='department_id']"
|
||||
hx-include="[name='department_id'],[name='guard_name']"
|
||||
>
|
||||
전체 거부
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="px-4 py-2 bg-gray-500 text-white text-sm font-medium rounded-lg hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-400"
|
||||
hx-post="/api/admin/department-permissions/deny-all"
|
||||
hx-post="/api/admin/department-permissions/reset"
|
||||
hx-target="#permission-matrix"
|
||||
hx-include="[name='department_id']"
|
||||
hx-include="[name='department_id'],[name='guard_name']"
|
||||
title="모든 메뉴의 조회(view) 권한만 허용"
|
||||
>
|
||||
초기화
|
||||
</button>
|
||||
@@ -99,11 +117,22 @@ function selectDepartment(button) {
|
||||
document.getElementById('action-buttons').style.display = 'block';
|
||||
}
|
||||
|
||||
// Guard 변경 시 권한 매트릭스 새로고침
|
||||
function reloadPermissions() {
|
||||
const selectedButton = document.querySelector('.department-button.bg-blue-700');
|
||||
if (selectedButton) {
|
||||
htmx.trigger(selectedButton, 'click');
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 로드 시 첫 번째 부서 자동 선택
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const firstButton = document.querySelector('.department-button');
|
||||
if (firstButton) {
|
||||
firstButton.click();
|
||||
// onclick 핸들러 실행
|
||||
selectDepartment(firstButton);
|
||||
// HTMX 이벤트 트리거
|
||||
htmx.trigger(firstButton, 'click');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -47,8 +47,9 @@
|
||||
{{ isset($permissions[$menu->id][$type]) && $permissions[$menu->id][$type] ? 'checked' : '' }}
|
||||
class="h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary cursor-pointer"
|
||||
hx-post="/api/admin/department-permissions/toggle"
|
||||
hx-trigger="click"
|
||||
hx-target="#permission-matrix"
|
||||
hx-include="[name='department_id']"
|
||||
hx-include="[name='department_id'],[name='guard_name']"
|
||||
hx-vals='{"menu_id": {{ $menu->id }}, "permission_type": "{{ $type }}"}'
|
||||
>
|
||||
</td>
|
||||
|
||||
@@ -22,6 +22,7 @@ class="role-button px-4 py-2 text-sm font-medium rounded-lg border transition-co
|
||||
data-role-name="{{ $role->name }}"
|
||||
hx-get="/api/admin/role-permissions/matrix"
|
||||
hx-target="#permission-matrix"
|
||||
hx-include="[name='guard_name']"
|
||||
hx-vals='{"role_id": {{ $role->id }}}'
|
||||
onclick="selectRole(this)"
|
||||
>
|
||||
@@ -39,12 +40,28 @@ class="role-button px-4 py-2 text-sm font-medium rounded-lg border transition-co
|
||||
<span class="text-sm font-medium text-gray-700" id="selected-role-name">선택된 역할</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="hidden" name="role_id" id="roleIdInput" value="">
|
||||
|
||||
<!-- Guard 선택 -->
|
||||
<span class="text-sm font-medium text-gray-700">Guard:</span>
|
||||
<select
|
||||
id="guardNameSelect"
|
||||
name="guard_name"
|
||||
class="px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-primary focus:border-primary"
|
||||
onchange="reloadPermissions()"
|
||||
>
|
||||
<option value="web" selected>Web</option>
|
||||
<option value="api">API</option>
|
||||
</select>
|
||||
|
||||
<!-- 구분선 -->
|
||||
<div class="h-8 w-px bg-gray-300 mx-1"></div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="px-4 py-2 bg-green-600 text-white text-sm font-medium rounded-lg hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500"
|
||||
hx-post="/api/admin/role-permissions/allow-all"
|
||||
hx-target="#permission-matrix"
|
||||
hx-include="[name='role_id']"
|
||||
hx-include="[name='role_id'],[name='guard_name']"
|
||||
>
|
||||
전체 허용
|
||||
</button>
|
||||
@@ -53,16 +70,17 @@ class="px-4 py-2 bg-green-600 text-white text-sm font-medium rounded-lg hover:bg
|
||||
class="px-4 py-2 bg-red-600 text-white text-sm font-medium rounded-lg hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500"
|
||||
hx-post="/api/admin/role-permissions/deny-all"
|
||||
hx-target="#permission-matrix"
|
||||
hx-include="[name='role_id']"
|
||||
hx-include="[name='role_id'],[name='guard_name']"
|
||||
>
|
||||
전체 거부
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="px-4 py-2 bg-gray-500 text-white text-sm font-medium rounded-lg hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-400"
|
||||
hx-post="/api/admin/role-permissions/deny-all"
|
||||
hx-post="/api/admin/role-permissions/reset"
|
||||
hx-target="#permission-matrix"
|
||||
hx-include="[name='role_id']"
|
||||
hx-include="[name='role_id'],[name='guard_name']"
|
||||
title="모든 메뉴의 조회(view) 권한만 허용"
|
||||
>
|
||||
초기화
|
||||
</button>
|
||||
@@ -99,11 +117,22 @@ function selectRole(button) {
|
||||
document.getElementById('action-buttons').style.display = 'block';
|
||||
}
|
||||
|
||||
// Guard 변경 시 권한 매트릭스 새로고침
|
||||
function reloadPermissions() {
|
||||
const selectedButton = document.querySelector('.role-button.bg-blue-700');
|
||||
if (selectedButton) {
|
||||
htmx.trigger(selectedButton, 'click');
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 로드 시 첫 번째 역할 자동 선택
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const firstButton = document.querySelector('.role-button');
|
||||
if (firstButton) {
|
||||
firstButton.click();
|
||||
// onclick 핸들러 실행
|
||||
selectRole(firstButton);
|
||||
// HTMX 이벤트 트리거
|
||||
htmx.trigger(firstButton, 'click');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
class="h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary cursor-pointer"
|
||||
hx-post="/api/admin/role-permissions/toggle"
|
||||
hx-target="#permission-matrix"
|
||||
hx-include="[name='role_id']"
|
||||
hx-include="[name='role_id'],[name='guard_name']"
|
||||
hx-vals='{"menu_id": {{ $menu->id }}, "permission_type": "{{ $type }}"}'
|
||||
>
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user