feat: [메뉴] 통합메뉴관리 - 글로벌에서 가져오기 기능 구현

- PULL 방식 메뉴 가져오기 (테넌트가 글로벌에서 선택적으로 가져옴)
- 모드 전환 UI (내 메뉴 / 글로벌에서 가져오기)
- 체크박스 선택으로 다중 메뉴 가져오기 지원
- 가져오기 모드에서 읽기 전용 상태 배지 표시
- hidden input으로 HTMX mode 파라미터 전달 수정
This commit is contained in:
2025-12-02 19:16:23 +09:00
parent d4051e20fa
commit 28b4ec8afd
6 changed files with 495 additions and 18 deletions

View File

@@ -20,19 +20,36 @@ public function __construct(
*/
public function index(Request $request): JsonResponse
{
$menus = $this->menuService->getMenus(
$request->all(),
$request->integer('per_page', 10)
);
$tenantId = session('selected_tenant_id');
$importMode = $request->get('mode') === 'import' && $tenantId;
if ($importMode) {
// 가져오기 모드: 복사 가능한 글로벌 메뉴 목록
$menus = $this->menuService->getAvailableGlobalMenus($tenantId);
} else {
// 일반 모드: 현재 범위의 메뉴 목록
$menus = $this->menuService->getMenus(
$request->all(),
$request->integer('per_page', 10)
);
}
// HTMX 요청인 경우 HTML 반환
if ($request->header('HX-Request')) {
$html = view('menus.partials.table', compact('menus'))->render();
$html = view('menus.partials.table', compact('menus', 'importMode'))->render();
return response()->json(['html' => $html]);
}
// 일반 API 요청인 경우 JSON 반환
if ($importMode) {
return response()->json([
'success' => true,
'data' => $menus,
'importMode' => true,
]);
}
return response()->json([
'success' => true,
'data' => $menus->items(),
@@ -350,4 +367,81 @@ public function move(Request $request): JsonResponse
], 500);
}
}
/**
* 복사 가능한 글로벌 메뉴 목록 조회
* (현재 테넌트에 존재하지 않는 글로벌 메뉴만)
*/
public function availableGlobal(Request $request): JsonResponse
{
$tenantId = session('selected_tenant_id');
if (! $tenantId) {
return response()->json([
'success' => false,
'message' => '테넌트를 선택해주세요.',
'menus' => [],
], 400);
}
try {
$menus = $this->menuService->getAvailableGlobalMenus($tenantId);
return response()->json([
'success' => true,
'menus' => $menus->map(function ($menu) {
return [
'id' => $menu->id,
'name' => $menu->name,
'url' => $menu->url,
'icon' => $menu->icon,
'depth' => $menu->depth ?? 0,
];
})->values(),
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => '메뉴 목록 조회에 실패했습니다: '.$e->getMessage(),
'menus' => [],
], 500);
}
}
/**
* 선택한 글로벌 메뉴를 현재 테넌트로 복사
*/
public function copyFromGlobal(Request $request): JsonResponse
{
$tenantId = session('selected_tenant_id');
if (! $tenantId) {
return response()->json([
'success' => false,
'message' => '테넌트를 선택해주세요.',
'copied' => 0,
], 400);
}
$validated = $request->validate([
'menu_ids' => 'required|array|min:1',
'menu_ids.*' => 'required|integer',
]);
try {
$result = $this->menuService->copyFromGlobal($tenantId, $validated['menu_ids']);
if (! $result['success']) {
return response()->json($result, 400);
}
return response()->json($result);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => '메뉴 복사에 실패했습니다: '.$e->getMessage(),
'copied' => 0,
], 500);
}
}
}