- RoleService, RoleController (Blade/API) 생성 - 역할 CRUD 기능 완성 (목록/생성/수정/삭제) - FormRequest 검증 (StoreRoleRequest, UpdateRoleRequest) - HTMX 패턴 적용 (index, create, edit) - 권한 선택 UI (체크박스, 전체 선택/해제) - Tenant Selector 통합 - 레이아웃 패턴 문서화 (LAYOUT_PATTERN.md) - Sidebar 메뉴에 역할 관리 추가 - Pagination partial 컴포넌트 추가 - Tenants 레이아웃 100% 폭으로 통일 주요 수정: - UpdateRoleRequest 라우트 파라미터 수정 (role → id) - RoleController permissions 조회 시 description 제거 - Conditional tenant filtering 적용
164 lines
9.7 KiB
PHP
164 lines
9.7 KiB
PHP
<!-- Sidebar -->
|
|
<aside class="w-64 bg-white shadow-lg flex-shrink-0">
|
|
<div class="flex flex-col h-full">
|
|
<!-- Logo / Brand -->
|
|
<div class="flex items-center justify-center h-16 border-b border-gray-200">
|
|
<span class="text-xl font-bold text-gray-900">{{ config('app.name') }}</span>
|
|
</div>
|
|
|
|
<!-- Navigation Menu -->
|
|
<nav class="flex-1 overflow-y-auto p-4">
|
|
<ul class="space-y-2">
|
|
<!-- 대시보드 -->
|
|
<li>
|
|
<a href="{{ route('dashboard') }}"
|
|
class="flex items-center gap-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-100 {{ request()->routeIs('dashboard') ? 'bg-primary text-white hover:bg-primary' : '' }}">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
|
|
</svg>
|
|
<span class="font-medium">대시보드</span>
|
|
</a>
|
|
</li>
|
|
|
|
<!-- 테넌트 관리 -->
|
|
<li>
|
|
<a href="{{ route('tenants.index') }}"
|
|
class="flex items-center gap-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-100 {{ request()->routeIs('tenants.*') ? 'bg-primary text-white hover:bg-primary' : '' }}">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
|
</svg>
|
|
<span class="font-medium">테넌트 관리</span>
|
|
</a>
|
|
</li>
|
|
|
|
<!-- 사용자 관리 -->
|
|
<li>
|
|
<a href="#"
|
|
class="flex items-center gap-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-100">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
|
|
</svg>
|
|
<span class="font-medium">사용자 관리</span>
|
|
</a>
|
|
</li>
|
|
|
|
<!-- 역할 관리 -->
|
|
<li>
|
|
<a href="{{ route('roles.index') }}"
|
|
class="flex items-center gap-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-100 {{ request()->routeIs('roles.*') ? 'bg-primary text-white hover:bg-primary' : '' }}">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
|
</svg>
|
|
<span class="font-medium">역할 관리</span>
|
|
</a>
|
|
</li>
|
|
|
|
<!-- 부서 관리 -->
|
|
<li>
|
|
<a href="#"
|
|
class="flex items-center gap-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-100">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
|
</svg>
|
|
<span class="font-medium">부서 관리</span>
|
|
</a>
|
|
</li>
|
|
|
|
<!-- 구분선 -->
|
|
<li class="py-2">
|
|
<div class="border-t border-gray-200"></div>
|
|
</li>
|
|
|
|
<!-- 제품 관리 -->
|
|
<li>
|
|
<a href="#"
|
|
class="flex items-center gap-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-100">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
|
|
</svg>
|
|
<span class="font-medium">제품 관리</span>
|
|
</a>
|
|
</li>
|
|
|
|
<!-- 자재 관리 -->
|
|
<li>
|
|
<a href="#"
|
|
class="flex items-center gap-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-100">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" />
|
|
</svg>
|
|
<span class="font-medium">자재 관리</span>
|
|
</a>
|
|
</li>
|
|
|
|
<!-- BOM 관리 -->
|
|
<li>
|
|
<a href="#"
|
|
class="flex items-center gap-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-100">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01" />
|
|
</svg>
|
|
<span class="font-medium">BOM 관리</span>
|
|
</a>
|
|
</li>
|
|
|
|
<!-- 카테고리 관리 -->
|
|
<li>
|
|
<a href="#"
|
|
class="flex items-center gap-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-100">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
|
|
</svg>
|
|
<span class="font-medium">카테고리 관리</span>
|
|
</a>
|
|
</li>
|
|
|
|
<!-- 구분선 -->
|
|
<li class="py-2">
|
|
<div class="border-t border-gray-200"></div>
|
|
</li>
|
|
|
|
<!-- 시스템 설정 -->
|
|
<li>
|
|
<a href="#"
|
|
class="flex items-center gap-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-100">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
</svg>
|
|
<span class="font-medium">시스템 설정</span>
|
|
</a>
|
|
</li>
|
|
|
|
<!-- 감사 로그 -->
|
|
<li>
|
|
<a href="#"
|
|
class="flex items-center gap-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-100">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
</svg>
|
|
<span class="font-medium">감사 로그</span>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
|
|
<!-- User Info (하단) -->
|
|
<div class="p-4 border-t border-gray-200">
|
|
<div class="flex items-center gap-3">
|
|
<div class="w-10 h-10 rounded-full bg-primary text-white flex items-center justify-center font-bold">
|
|
{{ strtoupper(substr(auth()->user()->name ?? 'U', 0, 1)) }}
|
|
</div>
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-sm font-medium text-gray-900 truncate">
|
|
{{ auth()->user()->name ?? 'User' }}
|
|
</p>
|
|
<p class="text-xs text-gray-500 truncate">
|
|
{{ auth()->user()->email }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</aside>
|