From 542c0bae94e3b70c3f1c1f74e1740a5969d0c8f9 Mon Sep 17 00:00:00 2001 From: kjs Date: Tue, 23 Dec 2025 17:06:21 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=EB=B3=B5=EC=82=AC=20=EC=9B=90=EB=B3=B8?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=B0=B8=EC=A1=B0=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend-node/src/services/menuCopyService.ts | 59 ++++++++++++++++---- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/backend-node/src/services/menuCopyService.ts b/backend-node/src/services/menuCopyService.ts index ac9768a1..6992baec 100644 --- a/backend-node/src/services/menuCopyService.ts +++ b/backend-node/src/services/menuCopyService.ts @@ -483,7 +483,8 @@ export class MenuCopyService { properties: any, screenIdMap: Map, flowIdMap: Map, - numberingRuleIdMap?: Map + numberingRuleIdMap?: Map, + menuIdMap?: Map ): any { if (!properties) return properties; @@ -496,7 +497,8 @@ export class MenuCopyService { screenIdMap, flowIdMap, "", - numberingRuleIdMap + numberingRuleIdMap, + menuIdMap ); return updated; @@ -510,7 +512,8 @@ export class MenuCopyService { screenIdMap: Map, flowIdMap: Map, path: string = "", - numberingRuleIdMap?: Map + numberingRuleIdMap?: Map, + menuIdMap?: Map ): void { if (!obj || typeof obj !== "object") return; @@ -522,7 +525,8 @@ export class MenuCopyService { screenIdMap, flowIdMap, `${path}[${index}]`, - numberingRuleIdMap + numberingRuleIdMap, + menuIdMap ); }); return; @@ -533,13 +537,16 @@ export class MenuCopyService { const value = obj[key]; const currentPath = path ? `${path}.${key}` : key; - // screen_id, screenId, targetScreenId, leftScreenId, rightScreenId 매핑 (숫자 또는 숫자 문자열) + // screen_id, screenId, targetScreenId, leftScreenId, rightScreenId, addModalScreenId, editModalScreenId, modalScreenId 매핑 (숫자 또는 숫자 문자열) if ( key === "screen_id" || key === "screenId" || key === "targetScreenId" || key === "leftScreenId" || - key === "rightScreenId" + key === "rightScreenId" || + key === "addModalScreenId" || + key === "editModalScreenId" || + key === "modalScreenId" ) { const numValue = typeof value === "number" ? value : parseInt(value); if (!isNaN(numValue) && numValue > 0) { @@ -549,6 +556,11 @@ export class MenuCopyService { logger.info( ` 🔗 화면 참조 업데이트 (${currentPath}): ${value} → ${newId}` ); + } else { + // 매핑이 없으면 경고 로그 (복사되지 않은 화면 참조) + logger.warn( + ` ⚠️ 화면 매핑 없음 (${currentPath}): ${value} - 원본 화면이 복사되지 않았을 수 있음` + ); } } } @@ -573,9 +585,9 @@ export class MenuCopyService { } } - // numberingRuleId 매핑 (문자열) + // numberingRuleId, ruleId 매핑 (문자열) - 채번규칙 참조 if ( - key === "numberingRuleId" && + (key === "numberingRuleId" || key === "ruleId") && numberingRuleIdMap && typeof value === "string" && value @@ -595,6 +607,25 @@ export class MenuCopyService { } } + // selectedMenuObjid 매핑 (메뉴 objid 참조) + if (key === "selectedMenuObjid" && menuIdMap) { + const numValue = typeof value === "number" ? value : parseInt(value); + if (!isNaN(numValue) && numValue > 0) { + const newId = menuIdMap.get(numValue); + if (newId) { + obj[key] = typeof value === "number" ? newId : String(newId); + logger.info( + ` 🔗 메뉴 참조 업데이트 (${currentPath}): ${value} → ${newId}` + ); + } else { + // 매핑이 없으면 경고 로그 (복사되지 않은 메뉴 참조) + logger.warn( + ` ⚠️ 메뉴 매핑 없음 (${currentPath}): ${value} - 원본 메뉴가 복사되지 않았을 수 있음` + ); + } + } + } + // 재귀 호출 if (typeof value === "object" && value !== null) { this.recursiveUpdateReferences( @@ -602,7 +633,8 @@ export class MenuCopyService { screenIdMap, flowIdMap, currentPath, - numberingRuleIdMap + numberingRuleIdMap, + menuIdMap ); } } @@ -981,7 +1013,8 @@ export class MenuCopyService { userId, client, screenNameConfig, - numberingRuleIdMap + numberingRuleIdMap, + menuIdMap ); // === 6단계: 화면-메뉴 할당 === @@ -1315,7 +1348,8 @@ export class MenuCopyService { removeText?: string; addPrefix?: string; }, - numberingRuleIdMap?: Map + numberingRuleIdMap?: Map, + menuIdMap?: Map ): Promise> { const screenIdMap = new Map(); @@ -1601,7 +1635,8 @@ export class MenuCopyService { layout.properties, screenIdMap, flowIdMap, - numberingRuleIdMap + numberingRuleIdMap, + menuIdMap ); layoutValues.push( From 755bbc0c58e734d53e8e2f70c95208e9b775c122 Mon Sep 17 00:00:00 2001 From: kjs Date: Tue, 23 Dec 2025 17:32:27 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=EB=B3=B5=EC=82=AC=20=EC=A7=84=EC=A7=9C?= =?UTF-8?q?=EC=A7=84=EC=A7=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend-node/src/services/menuCopyService.ts | 79 ++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/backend-node/src/services/menuCopyService.ts b/backend-node/src/services/menuCopyService.ts index 6992baec..075a8229 100644 --- a/backend-node/src/services/menuCopyService.ts +++ b/backend-node/src/services/menuCopyService.ts @@ -279,11 +279,90 @@ export class MenuCopyService { logger.debug(` 📐 분할 패널 우측 화면 참조 발견: ${numId}`); } } + + // 5) 모달 화면 ID (addModalScreenId, editModalScreenId, modalScreenId) + if (props?.componentConfig?.addModalScreenId) { + const addModalScreenId = props.componentConfig.addModalScreenId; + const numId = + typeof addModalScreenId === "number" + ? addModalScreenId + : parseInt(addModalScreenId); + if (!isNaN(numId) && numId > 0) { + referenced.push(numId); + logger.debug(` 📋 추가 모달 화면 참조 발견: ${numId}`); + } + } + + if (props?.componentConfig?.editModalScreenId) { + const editModalScreenId = props.componentConfig.editModalScreenId; + const numId = + typeof editModalScreenId === "number" + ? editModalScreenId + : parseInt(editModalScreenId); + if (!isNaN(numId) && numId > 0) { + referenced.push(numId); + logger.debug(` 📝 수정 모달 화면 참조 발견: ${numId}`); + } + } + + if (props?.componentConfig?.modalScreenId) { + const modalScreenId = props.componentConfig.modalScreenId; + const numId = + typeof modalScreenId === "number" + ? modalScreenId + : parseInt(modalScreenId); + if (!isNaN(numId) && numId > 0) { + referenced.push(numId); + logger.debug(` 🔲 모달 화면 참조 발견: ${numId}`); + } + } + + // 6) 재귀적으로 모든 properties에서 화면 ID 추출 (깊은 탐색) + this.extractScreenIdsFromObject(props, referenced); } return referenced; } + /** + * 객체 내부에서 화면 ID를 재귀적으로 추출 + */ + private extractScreenIdsFromObject(obj: any, referenced: number[]): void { + if (!obj || typeof obj !== "object") return; + + if (Array.isArray(obj)) { + for (const item of obj) { + this.extractScreenIdsFromObject(item, referenced); + } + return; + } + + for (const key of Object.keys(obj)) { + const value = obj[key]; + + // 화면 ID 키 패턴 확인 + if ( + key === "screenId" || + key === "targetScreenId" || + key === "leftScreenId" || + key === "rightScreenId" || + key === "addModalScreenId" || + key === "editModalScreenId" || + key === "modalScreenId" + ) { + const numId = typeof value === "number" ? value : parseInt(value); + if (!isNaN(numId) && numId > 0 && !referenced.includes(numId)) { + referenced.push(numId); + } + } + + // 재귀 탐색 + if (typeof value === "object" && value !== null) { + this.extractScreenIdsFromObject(value, referenced); + } + } + } + /** * 화면 수집 (중복 제거, 재귀적 참조 추적) */