From 3ddca95af59381c31e1fa8fd1dd1e73e0379a09d Mon Sep 17 00:00:00 2001 From: kjs Date: Thu, 13 Nov 2025 12:22:33 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=A9=94=EB=89=B4=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=ED=99=94=EB=A9=B4=20=ED=95=A0=EB=8B=B9=20?= =?UTF-8?q?=ED=95=B4=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 문제점 - URL 직접 입력 모드에서 빈 값으로 저장 시 menu_url은 비워지지만 - screen_code는 기존 값이 남아있어 화면 할당이 해제되지 않음 ## 해결방법 ### 백엔드 (adminController.ts) - updateMenu: menu_url이 비어있으면 screen_code도 null로 자동 설정 - 로직: menuUrl ? screenCode : null ### 프론트엔드 (MenuFormModal.tsx, menu.ts) - 화면 선택 시 screenCode도 함께 formData에 저장 - URL 타입 변경 시 screenCode 초기화 - MenuFormData 인터페이스에 screenCode 필드 추가 ## 동작 방식 1. 화면 할당: menuUrl + screenCode 함께 저장 2. URL 직접 입력: menuUrl만 저장, screenCode는 undefined 3. 빈 값 저장: menuUrl = null, screenCode = null (자동) 이제 메뉴에서 화면 할당을 완전히 해제할 수 있습니다. --- backend-node/src/controllers/adminController.ts | 12 +++++++++--- frontend/components/admin/MenuFormModal.tsx | 8 ++++++-- frontend/lib/api/menu.ts | 1 + 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/backend-node/src/controllers/adminController.ts b/backend-node/src/controllers/adminController.ts index e5a3c7b3..02a11996 100644 --- a/backend-node/src/controllers/adminController.ts +++ b/backend-node/src/controllers/adminController.ts @@ -1274,6 +1274,10 @@ export async function updateMenu( const companyCode = requestCompanyCode; + // menu_url이 비어있으면 screen_code도 null로 설정 + const menuUrl = menuData.menuUrl || null; + const screenCode = menuUrl ? menuData.screenCode || null : null; + // Raw Query를 사용한 메뉴 수정 const [updatedMenu] = await query( `UPDATE menu_info SET @@ -1288,8 +1292,9 @@ export async function updateMenu( system_name = $9, company_code = $10, lang_key = $11, - lang_key_desc = $12 - WHERE objid = $13 + lang_key_desc = $12, + screen_code = $13 + WHERE objid = $14 RETURNING *`, [ menuData.menuType ? Number(menuData.menuType) : null, @@ -1297,13 +1302,14 @@ export async function updateMenu( menuData.menuNameKor, menuData.menuNameEng || null, menuData.seq ? Number(menuData.seq) : null, - menuData.menuUrl || null, + menuUrl, menuData.menuDesc || null, menuData.status || "active", menuData.systemName || null, companyCode, menuData.langKey || null, menuData.langKeyDesc || null, + screenCode, Number(menuId), ] ); diff --git a/frontend/components/admin/MenuFormModal.tsx b/frontend/components/admin/MenuFormModal.tsx index 7c6f6aa5..33d2447e 100644 --- a/frontend/components/admin/MenuFormModal.tsx +++ b/frontend/components/admin/MenuFormModal.tsx @@ -161,6 +161,7 @@ export const MenuFormModal: React.FC = ({ setFormData((prev) => ({ ...prev, menuUrl: screenUrl, + screenCode: screen.screenCode, // 화면 코드도 함께 저장 })); // console.log("🖥️ 화면 선택 완료:", { @@ -207,10 +208,11 @@ export const MenuFormModal: React.FC = ({ if (type === "direct") { // 직접 입력 모드로 변경 시 선택된 화면 초기화 setSelectedScreen(null); - // URL 필드도 초기화 (사용자가 직접 입력할 수 있도록) + // URL 필드와 screenCode 초기화 (사용자가 직접 입력할 수 있도록) setFormData((prev) => ({ ...prev, menuUrl: "", + screenCode: undefined, // 화면 코드도 함께 초기화 })); } else { // 화면 할당 모드로 변경 시 @@ -230,12 +232,14 @@ export const MenuFormModal: React.FC = ({ setFormData((prev) => ({ ...prev, menuUrl: screenUrl, + screenCode: selectedScreen.screenCode, // 화면 코드도 함께 유지 })); } else { - // 선택된 화면이 없으면 URL만 초기화 + // 선택된 화면이 없으면 URL과 screenCode 초기화 setFormData((prev) => ({ ...prev, menuUrl: "", + screenCode: undefined, })); } } diff --git a/frontend/lib/api/menu.ts b/frontend/lib/api/menu.ts index 80156357..ad28996e 100644 --- a/frontend/lib/api/menu.ts +++ b/frontend/lib/api/menu.ts @@ -53,6 +53,7 @@ export interface MenuFormData { status: string; companyCode: string; langKey?: string; // 다국어 키 추가 + screenCode?: string; // 화면 코드 추가 } export interface LangKey {