feat: [메뉴] 통합메뉴관리 - 글로벌에서 가져오기 기능 구현
- PULL 방식 메뉴 가져오기 (테넌트가 글로벌에서 선택적으로 가져옴) - 모드 전환 UI (내 메뉴 / 글로벌에서 가져오기) - 체크박스 선택으로 다중 메뉴 가져오기 지원 - 가져오기 모드에서 읽기 전용 상태 배지 표시 - hidden input으로 HTMX mode 파라미터 전달 수정
This commit is contained in:
@@ -3,8 +3,10 @@
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Commons\Menu;
|
||||
use App\Models\Tenants\Tenant;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class MenuService
|
||||
{
|
||||
@@ -440,4 +442,114 @@ private function compactSiblings(?int $parentId): void
|
||||
$order++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 복사 가능한 글로벌 메뉴 목록 조회
|
||||
* (현재 테넌트에 존재하지 않는 글로벌 메뉴만)
|
||||
*/
|
||||
public function getAvailableGlobalMenus(int $tenantId): Collection
|
||||
{
|
||||
// 글로벌 메뉴 전체 조회
|
||||
$globalMenus = Menu::whereNull('tenant_id')
|
||||
->where('is_active', true)
|
||||
->orderBy('parent_id')
|
||||
->orderBy('sort_order')
|
||||
->get();
|
||||
|
||||
// 현재 테넌트에 이미 복사된 메뉴의 global_menu_id 목록
|
||||
$existingGlobalIds = Menu::where('tenant_id', $tenantId)
|
||||
->whereNotNull('global_menu_id')
|
||||
->pluck('global_menu_id')
|
||||
->toArray();
|
||||
|
||||
// 현재 테넌트에 없는 글로벌 메뉴만 필터링
|
||||
$availableMenus = $globalMenus->filter(function ($menu) use ($existingGlobalIds) {
|
||||
return ! in_array($menu->id, $existingGlobalIds);
|
||||
});
|
||||
|
||||
// 트리 구조로 정렬 (depth 정보 포함)
|
||||
return $this->flattenMenuTree($availableMenus);
|
||||
}
|
||||
|
||||
/**
|
||||
* 선택한 글로벌 메뉴를 현재 테넌트로 복사
|
||||
*/
|
||||
public function copyFromGlobal(int $tenantId, array $menuIds): array
|
||||
{
|
||||
if (empty($menuIds)) {
|
||||
return ['success' => false, 'message' => '복사할 메뉴를 선택해주세요.', 'copied' => 0];
|
||||
}
|
||||
|
||||
// 선택된 글로벌 메뉴 조회
|
||||
$globalMenus = Menu::whereNull('tenant_id')
|
||||
->whereIn('id', $menuIds)
|
||||
->orderBy('parent_id') // 부모 먼저 복사하기 위해
|
||||
->orderBy('sort_order')
|
||||
->get();
|
||||
|
||||
if ($globalMenus->isEmpty()) {
|
||||
return ['success' => false, 'message' => '유효한 글로벌 메뉴가 없습니다.', 'copied' => 0];
|
||||
}
|
||||
|
||||
$copied = 0;
|
||||
|
||||
return DB::transaction(function () use ($globalMenus, $tenantId, &$copied) {
|
||||
// global_menu_id → 새로 생성된 tenant menu id 매핑
|
||||
$idMapping = [];
|
||||
|
||||
foreach ($globalMenus as $globalMenu) {
|
||||
// 이미 복사된 메뉴인지 확인
|
||||
$exists = Menu::where('tenant_id', $tenantId)
|
||||
->where('global_menu_id', $globalMenu->id)
|
||||
->exists();
|
||||
|
||||
if ($exists) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 부모 메뉴 매핑 (글로벌 → 테넌트)
|
||||
$newParentId = null;
|
||||
if ($globalMenu->parent_id) {
|
||||
// 이번 복사에서 생성된 부모가 있는지 확인
|
||||
if (isset($idMapping[$globalMenu->parent_id])) {
|
||||
$newParentId = $idMapping[$globalMenu->parent_id];
|
||||
} else {
|
||||
// 기존에 복사된 부모 메뉴가 있는지 확인
|
||||
$parentTenantMenu = Menu::where('tenant_id', $tenantId)
|
||||
->where('global_menu_id', $globalMenu->parent_id)
|
||||
->first();
|
||||
$newParentId = $parentTenantMenu?->id;
|
||||
}
|
||||
}
|
||||
|
||||
// 새 테넌트 메뉴 생성
|
||||
$newMenu = Menu::create([
|
||||
'tenant_id' => $tenantId,
|
||||
'parent_id' => $newParentId,
|
||||
'global_menu_id' => $globalMenu->id,
|
||||
'name' => $globalMenu->name,
|
||||
'url' => $globalMenu->url,
|
||||
'icon' => $globalMenu->icon,
|
||||
'sort_order' => $globalMenu->sort_order,
|
||||
'is_active' => $globalMenu->is_active,
|
||||
'hidden' => $globalMenu->hidden,
|
||||
'is_external' => $globalMenu->is_external,
|
||||
'external_url' => $globalMenu->external_url,
|
||||
'is_customized' => false,
|
||||
'created_by' => auth()->id(),
|
||||
'updated_by' => auth()->id(),
|
||||
]);
|
||||
|
||||
// ID 매핑 저장 (자식 메뉴 복사 시 참조용)
|
||||
$idMapping[$globalMenu->id] = $newMenu->id;
|
||||
$copied++;
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => "{$copied}개 메뉴가 복사되었습니다.",
|
||||
'copied' => $copied,
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user