Files
sam-manage/resources/views/role-permissions/index.blade.php
hskwon 39ed2ac3e3 feat(user-modal): 사용자 정보 모달 및 컨텍스트 메뉴 확장
사용자 모달 기능:
- 사용자 정보 모달 팝업 (조회/삭제/수정)
- 권한 요약 정보 (Web/API 권한 카운트)
- 2x2 그리드 레이아웃 (테넌트, 역할, 부서, 권한)
- 테이블 행 클릭으로 모달 열기
- 권한 관리 링크 클릭 시 해당 사용자 자동 선택

컨텍스트 메뉴 확장:
- permission-analyze 페이지 사용자 이름에 컨텍스트 메뉴
- user-permissions 페이지 사용자 버튼에 컨텍스트 메뉴
- 사용자 모달 내 테넌트 칩에 컨텍스트 메뉴
- 헤더 테넌트 배지에 컨텍스트 메뉴
- 테넌트 메뉴에 "이 테넌트로 전환" 기능 추가
2025-11-27 20:05:27 +09:00

139 lines
7.0 KiB
PHP

@extends('layouts.app')
@section('title', '역할 권한 관리')
@section('content')
<!-- 페이지 헤더 -->
<div class="flex justify-between items-center mb-6">
<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">
@if($rolesByTenant)
{{-- 전체 테넌트 선택 : 테넌트 선택 안내 --}}
<div class="text-center py-8">
<div class="text-yellow-500 text-4xl mb-3">⚠️</div>
<p class="text-gray-700 font-medium mb-2">테넌트를 선택해주세요</p>
<p class="text-gray-500 text-sm">역할 권한을 관리하려면 상단 헤더에서 특정 테넌트를 선택해야 합니다.</p>
</div>
@else
{{-- 특정 테넌트 선택 : 기존 방식):firstAutoSelect 활성화 --}}
<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 bg-white text-gray-700 border-gray-300 hover:bg-gray-50"
data-role-id="{{ $role->id }}"
data-role-name="{{ $role->name }}"
data-guard-name="{{ $role->guard_name }}"
data-auto-select="{{ $loop->first ? 'true' : 'false' }}"
hx-get="/api/admin/role-permissions/matrix"
hx-target="#permission-matrix"
hx-include="[name='guard_name']"
hx-vals='{"role_id": {{ $role->id }}, "guard_name": "{{ $role->guard_name }}"}'
onclick="selectRole(this)"
>
<span>{{ $role->name }}</span>
<span class="ml-1 px-1.5 py-0.5 text-xs rounded {{ $role->guard_name === 'web' ? 'bg-blue-100 text-blue-600' : 'bg-green-100 text-green-600' }}">{{ $role->guard_name }}</span>
</button>
@endforeach
</div>
@endif
</div>
</div>
<!-- 액션 버튼 -->
<div class="bg-white rounded-lg shadow-sm mb-6" id="action-buttons" style="display: none;">
<div class="px-6 py-4 border-b border-gray-200">
<div class="flex items-center justify-between">
<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="">
<input type="hidden" name="guard_name" id="guardNameInput" value="">
<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'],[name='guard_name']"
>
전체 허용
</button>
<button
type="button"
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'],[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/reset"
hx-target="#permission-matrix"
hx-include="[name='role_id'],[name='guard_name']"
title="모든 메뉴의 조회(view) 권한만 허용"
>
초기화
</button>
</div>
</div>
</div>
</div>
<!-- 권한 매트릭스 테이블 -->
<div id="permission-matrix" class="bg-white rounded-lg shadow-sm">
@include('role-permissions.partials.empty-state')
</div>
<script>
function selectRole(button) {
// 모든 버튼의 활성 상태 제거
document.querySelectorAll('.role-button').forEach(btn => {
btn.classList.remove('bg-blue-700', 'text-white', 'border-blue-700', 'hover:bg-blue-800');
btn.classList.add('bg-white', 'text-gray-700', 'border-gray-300', 'hover:bg-gray-50');
});
// 클릭된 버튼 활성화
button.classList.remove('bg-white', 'text-gray-700', 'border-gray-300', 'hover:bg-gray-50');
button.classList.add('bg-blue-700', 'text-white', 'border-blue-700', 'hover:bg-blue-800');
// 역할 정보 저장
const roleId = button.getAttribute('data-role-id');
const roleName = button.getAttribute('data-role-name');
const guardName = button.getAttribute('data-guard-name');
const tenantName = button.getAttribute('data-tenant-name');
document.getElementById('roleIdInput').value = roleId;
document.getElementById('guardNameInput').value = guardName;
const guardBadge = guardName === 'web'
? '<span class="ml-1 px-1.5 py-0.5 text-xs rounded bg-blue-100 text-blue-600">web</span>'
: '<span class="ml-1 px-1.5 py-0.5 text-xs rounded bg-green-100 text-green-600">api</span>';
const displayName = tenantName ? `[${tenantName}] ${roleName}` : `${roleName}`;
document.getElementById('selected-role-name').innerHTML = displayName + ' 역할 ' + guardBadge;
// 액션 버튼 표시
document.getElementById('action-buttons').style.display = 'block';
}
// 페이지 로드 시 첫 번째 역할 자동 선택 (특정 테넌트 선택 시에만)
document.addEventListener('DOMContentLoaded', function() {
const autoSelectButton = document.querySelector('.role-button[data-auto-select="true"]');
if (autoSelectButton) {
// onclick 핸들러 실행
selectRole(autoSelectButton);
// HTMX 이벤트 트리거
htmx.trigger(autoSelectButton, 'click');
}
});
</script>
<script src="{{ asset('js/menu-tree.js') }}"></script>
@endsection