역할/부서 권한 관리 페이지 테넌트별 그룹핑 기능 추가
- 전체 테넌트 선택 시 역할/부서를 테넌트별로 그룹화하여 표시 - 테넌트별 섹션 헤더 추가 (회색 라벨) - 선택 시 [테넌트명] 역할/부서명 형식으로 표시 - 단일 테넌트 선택 시 기존 UI 유지
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Tenants\Department;
|
||||
use App\Models\Tenants\Tenant;
|
||||
use App\Services\DepartmentPermissionService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
@@ -22,14 +24,27 @@ public function index(Request $request)
|
||||
$tenantId = session('selected_tenant_id');
|
||||
|
||||
// 부서 목록 조회
|
||||
$departments = \App\Models\Tenants\Department::query();
|
||||
$departmentsQuery = Department::query()->orderBy('tenant_id')->orderBy('sort_order')->orderBy('name');
|
||||
|
||||
if ($tenantId && $tenantId !== 'all') {
|
||||
$departments->where('tenant_id', $tenantId);
|
||||
// 특정 테넌트 선택 시
|
||||
$departments = $departmentsQuery->where('tenant_id', $tenantId)->get();
|
||||
$departmentsByTenant = null;
|
||||
} else {
|
||||
// 전체 선택 시 테넌트별 그룹핑
|
||||
$departments = $departmentsQuery->get();
|
||||
$departmentsByTenant = $departments->groupBy('tenant_id');
|
||||
|
||||
// 테넌트 정보 로드
|
||||
$tenantIds = $departmentsByTenant->keys()->filter()->toArray();
|
||||
$tenants = Tenant::whereIn('id', $tenantIds)->pluck('company_name', 'id');
|
||||
}
|
||||
$departments = $departments->orderBy('sort_order')->orderBy('name')->get();
|
||||
|
||||
return view('department-permissions.index', [
|
||||
'departments' => $departments,
|
||||
'departmentsByTenant' => $departmentsByTenant ?? null,
|
||||
'tenants' => $tenants ?? collect(),
|
||||
'selectedTenantId' => $tenantId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Role;
|
||||
use App\Models\Tenants\Tenant;
|
||||
use App\Services\RolePermissionService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
@@ -22,14 +24,27 @@ public function index(Request $request)
|
||||
$tenantId = session('selected_tenant_id');
|
||||
|
||||
// 역할 목록 조회
|
||||
$roles = \App\Models\Role::query();
|
||||
$rolesQuery = Role::query()->orderBy('tenant_id')->orderBy('name');
|
||||
|
||||
if ($tenantId && $tenantId !== 'all') {
|
||||
$roles->where('tenant_id', $tenantId);
|
||||
// 특정 테넌트 선택 시
|
||||
$roles = $rolesQuery->where('tenant_id', $tenantId)->get();
|
||||
$rolesByTenant = null;
|
||||
} else {
|
||||
// 전체 선택 시 테넌트별 그룹핑
|
||||
$roles = $rolesQuery->get();
|
||||
$rolesByTenant = $roles->groupBy('tenant_id');
|
||||
|
||||
// 테넌트 정보 로드
|
||||
$tenantIds = $rolesByTenant->keys()->filter()->toArray();
|
||||
$tenants = Tenant::whereIn('id', $tenantIds)->pluck('company_name', 'id');
|
||||
}
|
||||
$roles = $roles->orderBy('name')->get();
|
||||
|
||||
return view('role-permissions.index', [
|
||||
'roles' => $roles,
|
||||
'rolesByTenant' => $rolesByTenant ?? null,
|
||||
'tenants' => $tenants ?? collect(),
|
||||
'selectedTenantId' => $tenantId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# 역할/부서 권한 관리 - 테넌트별 그룹핑
|
||||
|
||||
## 변경 일자
|
||||
2025-11-26
|
||||
|
||||
## 변경 목적
|
||||
- "전체" 테넌트 선택 시 역할/부서가 혼합되어 표시되는 문제 해결
|
||||
- 테넌트별로 그룹핑하여 가독성 향상
|
||||
|
||||
## 변경 파일
|
||||
|
||||
### 1. Controllers
|
||||
| 파일 | 변경 내용 |
|
||||
|------|----------|
|
||||
| `app/Http/Controllers/RolePermissionController.php` | 테넌트별 역할 그룹핑 로직 추가 |
|
||||
| `app/Http/Controllers/DepartmentPermissionController.php` | 테넌트별 부서 그룹핑 로직 추가 |
|
||||
|
||||
**주요 로직:**
|
||||
```php
|
||||
if ($tenantId && $tenantId !== 'all') {
|
||||
// 특정 테넌트 선택 시 기존 방식
|
||||
$roles = $rolesQuery->where('tenant_id', $tenantId)->get();
|
||||
$rolesByTenant = null;
|
||||
} else {
|
||||
// 전체 선택 시 테넌트별 그룹핑
|
||||
$roles = $rolesQuery->get();
|
||||
$rolesByTenant = $roles->groupBy('tenant_id');
|
||||
$tenantIds = $rolesByTenant->keys()->filter()->toArray();
|
||||
$tenants = Tenant::whereIn('id', $tenantIds)->pluck('company_name', 'id');
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Views
|
||||
| 파일 | 변경 내용 |
|
||||
|------|----------|
|
||||
| `resources/views/role-permissions/index.blade.php` | 테넌트별 섹션 헤더 및 그룹핑 UI |
|
||||
| `resources/views/department-permissions/index.blade.php` | 테넌트별 섹션 헤더 및 그룹핑 UI |
|
||||
|
||||
**UI 변경:**
|
||||
- 전체 테넌트 선택 시: 테넌트별 섹션으로 구분 (회색 라벨)
|
||||
- 선택된 역할/부서 표시: `[테넌트명] 역할명 역할` 형식
|
||||
- 기존 단일 테넌트 선택 시: 기존 UI 유지
|
||||
|
||||
## 테스트 결과
|
||||
- PHP 문법 검사: 통과
|
||||
- Laravel Pint: 통과
|
||||
- 브라우저 테스트: 테넌트별 그룹핑 정상 동작
|
||||
|
||||
## 관련 이슈
|
||||
- tenants 테이블 컬럼명: `company_name` (name 아님)
|
||||
@@ -11,25 +11,57 @@
|
||||
<!-- 부서 선택 -->
|
||||
<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">
|
||||
<span class="text-sm font-medium text-gray-700">부서 선택:</span>
|
||||
@foreach($departments as $department)
|
||||
<button
|
||||
type="button"
|
||||
class="department-button px-4 py-2 text-sm font-medium rounded-lg border transition-colors
|
||||
{{ $loop->first ? 'bg-blue-700 text-white border-blue-700' : 'bg-white text-gray-700 border-gray-300 hover:bg-gray-50' }}"
|
||||
data-department-id="{{ $department->id }}"
|
||||
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)"
|
||||
>
|
||||
{{ $department->name }}
|
||||
</button>
|
||||
@if($departmentsByTenant)
|
||||
{{-- 전체 테넌트 선택 시: 테넌트별 그룹핑 --}}
|
||||
@foreach($departmentsByTenant as $tenantId => $tenantDepartments)
|
||||
<div class="mb-4 last:mb-0">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="px-2 py-1 text-xs font-semibold bg-gray-100 text-gray-600 rounded">
|
||||
{{ $tenants[$tenantId] ?? '미지정' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-3 pl-2">
|
||||
@foreach($tenantDepartments as $department)
|
||||
<button
|
||||
type="button"
|
||||
class="department-button px-4 py-2 text-sm font-medium rounded-lg border transition-colors bg-white text-gray-700 border-gray-300 hover:bg-gray-50"
|
||||
data-department-id="{{ $department->id }}"
|
||||
data-department-name="{{ $department->name }}"
|
||||
data-tenant-name="{{ $tenants[$tenantId] ?? '미지정' }}"
|
||||
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)"
|
||||
>
|
||||
{{ $department->name }}
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
{{-- 특정 테넌트 선택 시: 기존 방식 --}}
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<span class="text-sm font-medium text-gray-700">부서 선택:</span>
|
||||
@foreach($departments as $department)
|
||||
<button
|
||||
type="button"
|
||||
class="department-button px-4 py-2 text-sm font-medium rounded-lg border transition-colors
|
||||
{{ $loop->first ? 'bg-blue-700 text-white border-blue-700' : 'bg-white text-gray-700 border-gray-300 hover:bg-gray-50' }}"
|
||||
data-department-id="{{ $department->id }}"
|
||||
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)"
|
||||
>
|
||||
{{ $department->name }}
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -109,9 +141,11 @@ function selectDepartment(button) {
|
||||
// 부서 정보 저장
|
||||
const departmentId = button.getAttribute('data-department-id');
|
||||
const departmentName = button.getAttribute('data-department-name');
|
||||
const tenantName = button.getAttribute('data-tenant-name');
|
||||
|
||||
document.getElementById('departmentIdInput').value = departmentId;
|
||||
document.getElementById('selected-department-name').textContent = departmentName + ' 부서';
|
||||
const displayName = tenantName ? `[${tenantName}] ${departmentName} 부서` : `${departmentName} 부서`;
|
||||
document.getElementById('selected-department-name').textContent = displayName;
|
||||
|
||||
// 액션 버튼 표시
|
||||
document.getElementById('action-buttons').style.display = 'block';
|
||||
|
||||
@@ -11,25 +11,57 @@
|
||||
<!-- 역할 선택 버튼 -->
|
||||
<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">
|
||||
<span class="text-sm font-medium text-gray-700">역할 선택:</span>
|
||||
@foreach($roles as $role)
|
||||
<button
|
||||
type="button"
|
||||
class="role-button px-4 py-2 text-sm font-medium rounded-lg border transition-colors
|
||||
{{ $loop->first ? 'bg-blue-700 text-white border-blue-700' : 'bg-white text-gray-700 border-gray-300 hover:bg-gray-50' }}"
|
||||
data-role-id="{{ $role->id }}"
|
||||
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)"
|
||||
>
|
||||
{{ $role->name }}
|
||||
</button>
|
||||
@if($rolesByTenant)
|
||||
{{-- 전체 테넌트 선택 시: 테넌트별 그룹핑 --}}
|
||||
@foreach($rolesByTenant as $tenantId => $tenantRoles)
|
||||
<div class="mb-4 last:mb-0">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="px-2 py-1 text-xs font-semibold bg-gray-100 text-gray-600 rounded">
|
||||
{{ $tenants[$tenantId] ?? '미지정' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-3 pl-2">
|
||||
@foreach($tenantRoles as $role)
|
||||
<button
|
||||
type="button"
|
||||
class="role-button px-4 py-2 text-sm font-medium rounded-lg border transition-colors bg-white text-gray-700 border-gray-300 hover:bg-gray-50"
|
||||
data-role-id="{{ $role->id }}"
|
||||
data-role-name="{{ $role->name }}"
|
||||
data-tenant-name="{{ $tenants[$tenantId] ?? '미지정' }}"
|
||||
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)"
|
||||
>
|
||||
{{ $role->name }}
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
{{-- 특정 테넌트 선택 시: 기존 방식 --}}
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<span class="text-sm font-medium text-gray-700">역할 선택:</span>
|
||||
@foreach($roles as $role)
|
||||
<button
|
||||
type="button"
|
||||
class="role-button px-4 py-2 text-sm font-medium rounded-lg border transition-colors
|
||||
{{ $loop->first ? 'bg-blue-700 text-white border-blue-700' : 'bg-white text-gray-700 border-gray-300 hover:bg-gray-50' }}"
|
||||
data-role-id="{{ $role->id }}"
|
||||
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)"
|
||||
>
|
||||
{{ $role->name }}
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -109,9 +141,11 @@ function selectRole(button) {
|
||||
// 역할 정보 저장
|
||||
const roleId = button.getAttribute('data-role-id');
|
||||
const roleName = button.getAttribute('data-role-name');
|
||||
const tenantName = button.getAttribute('data-tenant-name');
|
||||
|
||||
document.getElementById('roleIdInput').value = roleId;
|
||||
document.getElementById('selected-role-name').textContent = roleName + ' 역할';
|
||||
const displayName = tenantName ? `[${tenantName}] ${roleName} 역할` : `${roleName} 역할`;
|
||||
document.getElementById('selected-role-name').textContent = displayName;
|
||||
|
||||
// 액션 버튼 표시
|
||||
document.getElementById('action-buttons').style.display = 'block';
|
||||
|
||||
Reference in New Issue
Block a user