diff --git a/app/Controllers/Admin/Menu.php b/app/Controllers/Admin/Menu.php index fc5f125..bf7280e 100644 --- a/app/Controllers/Admin/Menu.php +++ b/app/Controllers/Admin/Menu.php @@ -210,7 +210,41 @@ class Menu extends BaseController 'mm_level' => $this->normalizeMmLevel((int) $row->mt_idx), 'mm_is_view' => $this->request->getPost('mm_is_view') ? 'Y' : 'N', ]; + + // 위치(상위↔하위) 변경 지원: mm_pidx 가 바뀌면 상위/하위로 이동 + $oldPidx = (int) $row->mm_pidx; + $newPidx = (int) $this->request->getPost('mm_pidx'); + $newDep = $newPidx > 0 ? 1 : 0; + $positionChanged = $newPidx !== $oldPidx; + if ($positionChanged) { + if ($newPidx === $id) { + return $this->menusRedirect((int) $row->mt_idx)->with('error', '자기 자신을 상위 메뉴로 지정할 수 없습니다.'); + } + // 하위 메뉴를 보유한 상위 메뉴는 하위로 변경 불가(2단 구조 유지) + $childCnt = $this->menuModel->where('mt_idx', (int) $row->mt_idx)->where('lg_idx', $lgIdx)->where('mm_pidx', $id)->countAllResults(); + if ($newPidx > 0 && $childCnt > 0) { + return $this->menusRedirect((int) $row->mt_idx)->with('error', '하위 메뉴가 있는 상위 메뉴는 하위로 변경할 수 없습니다. 먼저 하위 메뉴를 옮겨 주세요.'); + } + if ($newPidx > 0) { + $parent = $this->menuModel->find($newPidx); + if (! $parent || (int) $parent->lg_idx !== $lgIdx || (int) $parent->mt_idx !== (int) $row->mt_idx || (int) $parent->mm_dep !== 0) { + return $this->menusRedirect((int) $row->mt_idx)->with('error', '올바른 상위 메뉴를 선택해 주세요.'); + } + } + $data['mm_pidx'] = $newPidx; + $data['mm_dep'] = $newDep; + $data['mm_num'] = $this->menuModel->getNextNum((int) $row->mt_idx, $lgIdx, $newPidx, $newDep); + } + $this->menuModel->update($id, $data); + if ($positionChanged) { + if ($oldPidx > 0) { + $this->menuModel->updateCnode($oldPidx, -1); + } + if ($newPidx > 0) { + $this->menuModel->updateCnode($newPidx, 1); + } + } $this->menuModel->pruneInventoryManagementMenus((int) $row->mt_idx, $lgIdx); $this->menuModel->syncTypeToAllLgs((int) $row->mt_idx, $lgIdx); return $this->menusRedirect((int) $row->mt_idx)->with('success', '메뉴가 수정되었습니다.'); diff --git a/app/Models/MenuModel.php b/app/Models/MenuModel.php index 00213ca..be5d073 100644 --- a/app/Models/MenuModel.php +++ b/app/Models/MenuModel.php @@ -270,6 +270,13 @@ class MenuModel extends Model ->get() ->getResultArray(); + // 깊이(dep) 오름차순으로 그룹핑 — 상위부터 삽입해 자식의 mm_pidx를 새 ID로 재매핑 + $byDep = []; + foreach ($source as $row) { + $byDep[(int) ($row->mm_dep ?? 0)][] = $row; + } + ksort($byDep); + foreach ($lgRows as $lgRow) { $destLg = (int) ($lgRow['lg_idx'] ?? 0); if ($destLg <= 0 || $destLg === $sourceLg) { @@ -281,28 +288,41 @@ class MenuModel extends Model ->where('lg_idx', $destLg) ->delete(); + // 원격 DB 왕복 최소화: 레벨(dep)별로 batch insert 후, 삽입 순서(mm_idx ASC)로 old→new ID 매핑 $idMap = []; - foreach ($source as $row) { - $oldId = (int) ($row->mm_idx ?? 0); - $oldP = (int) ($row->mm_pidx ?? 0); - $newPidx = 0; - if ($oldP > 0 && isset($idMap[$oldP])) { - $newPidx = (int) $idMap[$oldP]; + foreach ($byDep as $dep => $levelRows) { + $batch = []; + foreach ($levelRows as $row) { + $oldP = (int) ($row->mm_pidx ?? 0); + $newPidx = ($oldP > 0 && isset($idMap[$oldP])) ? (int) $idMap[$oldP] : 0; + $batch[] = [ + 'mt_idx' => $mtIdx, + 'lg_idx' => $destLg, + 'mm_name' => (string) ($row->mm_name ?? ''), + 'mm_link' => (string) ($row->mm_link ?? ''), + 'mm_pidx' => $newPidx, + 'mm_dep' => (int) $dep, + 'mm_num' => (int) ($row->mm_num ?? 0), + 'mm_cnode' => (int) ($row->mm_cnode ?? 0), + 'mm_level' => (string) ($row->mm_level ?? ''), + 'mm_is_view' => (string) ($row->mm_is_view ?? 'Y'), + ]; + } + if ($batch === []) { + continue; + } + $this->insertBatch($batch); + // 방금 삽입한 이 레벨의 행을 삽입 순서(mm_idx ASC)대로 조회해 원본과 1:1 매핑 + $inserted = $this->where('mt_idx', $mtIdx) + ->where('lg_idx', $destLg) + ->where('mm_dep', (int) $dep) + ->orderBy('mm_idx', 'ASC') + ->findAll(); + foreach ($levelRows as $i => $row) { + if (isset($inserted[$i])) { + $idMap[(int) ($row->mm_idx ?? 0)] = (int) $inserted[$i]->mm_idx; + } } - - $this->insert([ - 'mt_idx' => $mtIdx, - 'lg_idx' => $destLg, - 'mm_name' => (string) ($row->mm_name ?? ''), - 'mm_link' => (string) ($row->mm_link ?? ''), - 'mm_pidx' => $newPidx, - 'mm_dep' => (int) ($row->mm_dep ?? 0), - 'mm_num' => (int) ($row->mm_num ?? 0), - 'mm_cnode' => (int) ($row->mm_cnode ?? 0), - 'mm_level' => (string) ($row->mm_level ?? ''), - 'mm_is_view' => (string) ($row->mm_is_view ?? 'Y'), - ]); - $idMap[$oldId] = (int) $this->getInsertID(); } $this->db->transComplete(); } diff --git a/app/Views/admin/menu/index.php b/app/Views/admin/menu/index.php index 010e8e1..99ab50d 100644 --- a/app/Views/admin/menu/index.php +++ b/app/Views/admin/menu/index.php @@ -145,7 +145,8 @@ $adminMenuListResolveHref = static function (string $rawLink) use ($menuListReso data-link="= esc($row->mm_link) ?>" data-level="= esc($row->mm_level) ?>" data-view="= (string) $row->mm_is_view ?>" - data-dep="= (int) $row->mm_dep ?>"> + data-dep="= (int) $row->mm_dep ?>" + data-pidx="= (int) $row->mm_pidx ?>"> 수정 @@ -190,6 +191,26 @@ $adminMenuListResolveHref = static function (string $rawLink) use ($menuListReso +