Files
sam-manage/resources/views/menus/partials/table.blade.php
hskwon 79aebfa148 메뉴 관리 기능 개선
- 트리 구조 정렬 및 표시 (무제한 depth 지원)
- 접기/펼치기 기능 추가 (재귀적 처리)
- 활성/숨김 상태 토글 기능 (실시간 업데이트)
- 테넌트 필터링 (전체 선택 시 마스터 메뉴만 표시)
- UI 개선 (토글 버튼, 외부 메뉴 표시)

추가된 파일:
- MenuService: 비즈니스 로직 처리
- MenuController (API/Web): 라우트 처리
- MenuRequest: 유효성 검증
- views/menus/: 메뉴 관리 뷰

수정된 파일:
- routes/api.php, web.php: 메뉴 라우트 추가
2025-11-24 22:02:09 +09:00

125 lines
7.3 KiB
PHP

<div class="bg-white rounded-lg shadow-sm overflow-hidden">
<table class="w-full">
<thead class="bg-gray-50 border-b">
<tr>
<th class="px-6 py-3 text-left text-sm font-semibold text-gray-700 uppercase tracking-wider">ID</th>
<th class="px-6 py-3 text-left text-sm font-semibold text-gray-700 uppercase tracking-wider">메뉴명</th>
<th class="px-6 py-3 text-left text-sm font-semibold text-gray-700 uppercase tracking-wider">URL</th>
<th class="px-6 py-3 text-left text-sm font-semibold text-gray-700 uppercase tracking-wider">정렬</th>
<th class="px-6 py-3 text-center text-sm font-semibold text-gray-700 uppercase tracking-wider">활성</th>
<th class="px-6 py-3 text-center text-sm font-semibold text-gray-700 uppercase tracking-wider">숨김</th>
<th class="px-6 py-3 text-left text-sm font-semibold text-gray-700 uppercase tracking-wider">작업</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
@forelse($menus as $menu)
<tr class="hover:bg-gray-50 menu-row"
data-menu-id="{{ $menu->id }}"
data-parent-id="{{ $menu->parent_id ?? '' }}"
data-depth="{{ $menu->depth ?? 0 }}">
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{{ $menu->id }}
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center" style="padding-left: {{ ($menu->depth ?? 0) * 20 }}px;">
@if($menu->has_children)
<button type="button"
onclick="toggleChildren({{ $menu->id }})"
class="mr-1 text-gray-500 hover:text-gray-700 focus:outline-none toggle-btn"
data-menu-id="{{ $menu->id }}">
<svg class="w-4 h-4 transform transition-transform" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
</svg>
</button>
@else
<span class="w-4 mr-1"></span>
@endif
@if(($menu->depth ?? 0) > 0)
<span class="mr-2 text-gray-400"></span>
@endif
<div>
<div class="text-sm font-medium text-gray-900">{{ $menu->name }}</div>
@if($menu->is_external)
<span class="text-xs text-blue-600">(외부)</span>
@endif
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
@if($menu->is_external && $menu->external_url)
<a href="{{ $menu->external_url }}" target="_blank" class="text-blue-600 hover:underline">
{{ Str::limit($menu->external_url, 30) }}
</a>
@elseif($menu->url)
{{ $menu->url }}
@else
-
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{ $menu->sort_order ?? 0 }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-center">
@if(!$menu->deleted_at)
<button type="button"
onclick="toggleActive({{ $menu->id }})"
class="relative inline-flex h-4 w-8 items-center rounded-full transition-colors focus:outline-none focus:ring-1 focus:ring-blue-500 focus:ring-offset-1 {{ $menu->is_active ? 'bg-blue-500' : 'bg-gray-400' }}">
<span class="inline-block h-3 w-3 transform rounded-full bg-white shadow-sm transition-transform {{ $menu->is_active ? 'translate-x-4' : 'translate-x-0.5' }}"></span>
</button>
@else
<span class="text-gray-400">-</span>
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-center">
@if(!$menu->deleted_at)
<button type="button"
onclick="toggleHidden({{ $menu->id }})"
class="relative inline-flex h-4 w-8 items-center rounded-full transition-colors focus:outline-none focus:ring-1 focus:ring-amber-500 focus:ring-offset-1 {{ $menu->hidden ? 'bg-amber-500' : 'bg-gray-400' }}">
<span class="inline-block h-3 w-3 transform rounded-full bg-white shadow-sm transition-transform {{ $menu->hidden ? 'translate-x-4' : 'translate-x-0.5' }}"></span>
</button>
@else
<span class="text-gray-400">-</span>
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
@if($menu->deleted_at)
<!-- 삭제된 항목 -->
<button onclick="confirmRestore({{ $menu->id }}, '{{ $menu->name }}')"
class="text-green-600 hover:text-green-900 mr-3">
복원
</button>
@if(auth()->user()?->is_super_admin)
<button onclick="confirmForceDelete({{ $menu->id }}, '{{ $menu->name }}')"
class="text-red-600 hover:text-red-900">
영구삭제
</button>
@endif
@else
<!-- 활성 항목 -->
<a href="{{ route('menus.edit', $menu->id) }}" class="text-blue-600 hover:text-blue-900 mr-3">
수정
</a>
<button onclick="confirmDelete({{ $menu->id }}, '{{ $menu->name }}')" class="text-red-600 hover:text-red-900">
삭제
</button>
@endif
</td>
</tr>
@empty
<tr>
<td colspan="7" class="px-6 py-4 text-center text-gray-500">
메뉴가 없습니다.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<!-- 페이지네이션 -->
@include('partials.pagination', [
'paginator' => $menus,
'target' => '#menu-table',
'includeForm' => '#filterForm'
])