feat: 메뉴 삭제 및 동기화 기능 개선
- 메뉴 삭제 시 하위 메뉴를 재귀적으로 수집하여 관련 데이터 정리 기능 추가 - 메뉴 삭제 성공 시 삭제된 메뉴와 하위 메뉴 수를 포함한 응답 메시지 개선 - 메뉴 복제 시 항상 활성화 상태로 설정 - 화면-메뉴 동기화 진행 상태를 사용자에게 알리기 위한 프로그레스 메시지 추가 - 최상위 회사 폴더는 메뉴로 생성하지 않고 스킵하는 로직 추가 - 동기화 진행 중 오버레이 UI 개선
This commit is contained in:
@@ -142,7 +142,7 @@ export async function syncScreenGroupsToMenu(
|
||||
const newObjid = Date.now();
|
||||
const createRootQuery = `
|
||||
INSERT INTO menu_info (objid, parent_obj_id, menu_name_kor, menu_name_eng, seq, menu_type, company_code, writer, regdate, status)
|
||||
VALUES ($1, 0, '사용자', 'User', 1, 1, $2, $3, NOW(), 'Y')
|
||||
VALUES ($1, 0, '사용자', 'User', 1, 1, $2, $3, NOW(), 'active')
|
||||
RETURNING objid
|
||||
`;
|
||||
const createRootResult = await client.query(createRootQuery, [newObjid, companyCode, userId]);
|
||||
@@ -159,12 +159,36 @@ export async function syncScreenGroupsToMenu(
|
||||
groupIdToName.set(g.id, g.group_name?.trim().toLowerCase() || '');
|
||||
});
|
||||
|
||||
// 5. 각 screen_group 처리
|
||||
// 5. 최상위 회사 폴더 ID 찾기 (level 0, parent_group_id IS NULL)
|
||||
// 이 폴더는 메뉴로 생성하지 않고, 하위 폴더들을 사용자 루트 바로 아래에 배치
|
||||
const topLevelCompanyFolderIds = new Set<number>();
|
||||
for (const group of screenGroupsResult.rows) {
|
||||
if (group.group_level === 0 && group.parent_group_id === null) {
|
||||
topLevelCompanyFolderIds.add(group.id);
|
||||
// 최상위 폴더 → 사용자 루트에 매핑 (하위 폴더의 부모로 사용)
|
||||
groupToMenuMap.set(group.id, userMenuRootObjid!);
|
||||
logger.info("최상위 회사 폴더 스킵", { groupId: group.id, groupName: group.group_name });
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 각 screen_group 처리
|
||||
for (const group of screenGroupsResult.rows) {
|
||||
const groupId = group.id;
|
||||
const groupName = group.group_name?.trim();
|
||||
const groupNameLower = groupName?.toLowerCase() || '';
|
||||
|
||||
// 최상위 회사 폴더는 메뉴로 생성하지 않고 스킵
|
||||
if (topLevelCompanyFolderIds.has(groupId)) {
|
||||
result.skipped++;
|
||||
result.details.push({
|
||||
action: 'skipped',
|
||||
sourceName: groupName,
|
||||
sourceId: groupId,
|
||||
reason: '최상위 회사 폴더 (메뉴 생성 스킵)',
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// 이미 연결된 경우 - 실제로 메뉴가 존재하는지 확인
|
||||
if (group.menu_objid) {
|
||||
const menuExists = existingMenuObjids.has(Number(group.menu_objid));
|
||||
@@ -237,11 +261,17 @@ export async function syncScreenGroupsToMenu(
|
||||
const newObjid = Date.now() + groupId; // 고유 ID 보장
|
||||
|
||||
// 부모 메뉴 objid 결정
|
||||
// 우선순위: groupToMenuMap > parent_menu_objid (존재 확인 필수)
|
||||
let parentMenuObjid = userMenuRootObjid;
|
||||
if (group.parent_group_id && group.parent_menu_objid) {
|
||||
parentMenuObjid = Number(group.parent_menu_objid);
|
||||
} else if (group.parent_group_id && groupToMenuMap.has(group.parent_group_id)) {
|
||||
if (group.parent_group_id && groupToMenuMap.has(group.parent_group_id)) {
|
||||
// 현재 트랜잭션에서 생성된 부모 메뉴 사용
|
||||
parentMenuObjid = groupToMenuMap.get(group.parent_group_id)!;
|
||||
} else if (group.parent_group_id && group.parent_menu_objid) {
|
||||
// 기존 parent_menu_objid가 실제로 존재하는지 확인
|
||||
const parentMenuExists = existingMenuObjids.has(Number(group.parent_menu_objid));
|
||||
if (parentMenuExists) {
|
||||
parentMenuObjid = Number(group.parent_menu_objid);
|
||||
}
|
||||
}
|
||||
|
||||
// 같은 부모 아래에서 가장 높은 seq 조회 후 +1
|
||||
@@ -261,7 +291,7 @@ export async function syncScreenGroupsToMenu(
|
||||
INSERT INTO menu_info (
|
||||
objid, parent_obj_id, menu_name_kor, menu_name_eng,
|
||||
seq, menu_type, company_code, writer, regdate, status, screen_group_id, menu_desc
|
||||
) VALUES ($1, $2, $3, $4, $5, 1, $6, $7, NOW(), 'Y', $8, $9)
|
||||
) VALUES ($1, $2, $3, $4, $5, 1, $6, $7, NOW(), 'active', $8, $9)
|
||||
RETURNING objid
|
||||
`;
|
||||
await client.query(insertMenuQuery, [
|
||||
|
||||
Reference in New Issue
Block a user