feat: 메뉴 복사 기능 - 2단계 복사 방식으로 화면 참조 매핑 문제 해결
- 문제: 화면 복사 시 참조되는 화면이 아직 복사되지 않아 screenIdMap에 매핑 정보가 없었음 - 해결: 2단계 복사 방식 도입 1단계: 모든 screen_definitions 먼저 복사하여 screenIdMap 완성 2단계: screen_layouts 복사하면서 완성된 screenIdMap으로 참조 업데이트 - 결과: targetScreenId가 올바르게 새 회사의 화면 ID로 매핑됨 (예: 149 → 517) - 추가: 화면 수집 시 문자열 타입 ID도 올바르게 파싱하도록 개선 - 추가: 참조 화면 발견 및 업데이트 로그 추가 관련 파일: - backend-node/src/services/menuCopyService.ts - db/migrations/1003_add_source_menu_objid_to_menu_info.sql - db/scripts/cleanup_company_11_*.sql
This commit is contained in:
@@ -9,6 +9,7 @@ import { AdminService } from "../services/adminService";
|
||||
import { EncryptUtil } from "../utils/encryptUtil";
|
||||
import { FileSystemManager } from "../utils/fileSystemManager";
|
||||
import { validateBusinessNumber } from "../utils/businessNumberValidator";
|
||||
import { MenuCopyService } from "../services/menuCopyService";
|
||||
|
||||
/**
|
||||
* 관리자 메뉴 목록 조회
|
||||
@@ -3253,3 +3254,84 @@ export async function getTableSchema(
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 메뉴 복사
|
||||
* POST /api/admin/menus/:menuObjid/copy
|
||||
*/
|
||||
export async function copyMenu(
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> {
|
||||
try {
|
||||
const { menuObjid } = req.params;
|
||||
const { targetCompanyCode } = req.body;
|
||||
const userId = req.user!.userId;
|
||||
const userCompanyCode = req.user!.companyCode;
|
||||
const userType = req.user!.userType;
|
||||
const isSuperAdmin = req.user!.isSuperAdmin;
|
||||
|
||||
logger.info(`
|
||||
=== 메뉴 복사 API 호출 ===
|
||||
menuObjid: ${menuObjid}
|
||||
targetCompanyCode: ${targetCompanyCode}
|
||||
userId: ${userId}
|
||||
userCompanyCode: ${userCompanyCode}
|
||||
userType: ${userType}
|
||||
isSuperAdmin: ${isSuperAdmin}
|
||||
`);
|
||||
|
||||
// 권한 체크: 최고 관리자만 가능
|
||||
if (!isSuperAdmin && userType !== "SUPER_ADMIN") {
|
||||
logger.warn(`권한 없음: ${userId} (userType=${userType}, company_code=${userCompanyCode})`);
|
||||
res.status(403).json({
|
||||
success: false,
|
||||
message: "메뉴 복사는 최고 관리자(SUPER_ADMIN)만 가능합니다",
|
||||
error: {
|
||||
code: "FORBIDDEN",
|
||||
details: "Only super admin can copy menus",
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 필수 파라미터 검증
|
||||
if (!menuObjid || !targetCompanyCode) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
message: "필수 파라미터가 누락되었습니다",
|
||||
error: {
|
||||
code: "MISSING_PARAMETERS",
|
||||
details: "menuObjid and targetCompanyCode are required",
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 메뉴 복사 실행
|
||||
const menuCopyService = new MenuCopyService();
|
||||
const result = await menuCopyService.copyMenu(
|
||||
parseInt(menuObjid, 10),
|
||||
targetCompanyCode,
|
||||
userId
|
||||
);
|
||||
|
||||
logger.info("✅ 메뉴 복사 API 성공");
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: "메뉴 복사 완료",
|
||||
data: result,
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error("❌ 메뉴 복사 API 실패:", error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: "메뉴 복사 중 오류가 발생했습니다",
|
||||
error: {
|
||||
code: "MENU_COPY_ERROR",
|
||||
details: error.message || "Unknown error",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
deleteMenu, // 메뉴 삭제
|
||||
deleteMenusBatch, // 메뉴 일괄 삭제
|
||||
toggleMenuStatus, // 메뉴 상태 토글
|
||||
copyMenu, // 메뉴 복사
|
||||
getUserList,
|
||||
getUserInfo, // 사용자 상세 조회
|
||||
getUserHistory, // 사용자 변경이력 조회
|
||||
@@ -39,6 +40,7 @@ router.get("/menus", getAdminMenus);
|
||||
router.get("/user-menus", getUserMenus);
|
||||
router.get("/menus/:menuId", getMenuInfo);
|
||||
router.post("/menus", saveMenu); // 메뉴 추가
|
||||
router.post("/menus/:menuObjid/copy", copyMenu); // 메뉴 복사 (NEW!)
|
||||
router.put("/menus/:menuId", updateMenu); // 메뉴 수정
|
||||
router.put("/menus/:menuId/toggle", toggleMenuStatus); // 메뉴 상태 토글
|
||||
router.delete("/menus/batch", deleteMenusBatch); // 메뉴 일괄 삭제 (순서 중요!)
|
||||
|
||||
1439
backend-node/src/services/menuCopyService.ts
Normal file
1439
backend-node/src/services/menuCopyService.ts
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user