feat: 화면 관리 및 메뉴 동기화 기능 개선

- 화면 그룹 컨트롤러 기능 확장
- 메뉴 복사 서비스 개선
- 메뉴-화면 동기화 서비스 추가
- 번호 규칙 서비스 개선
- 화면 관리 서비스 확장
- CopyScreenModal 기능 개선
- DataFlowPanel, FieldJoinPanel 수정
This commit is contained in:
DDD1542
2026-01-21 11:53:51 +09:00
parent 40a226ca30
commit ad8b1791bc
15 changed files with 3895 additions and 136 deletions

View File

@@ -834,3 +834,264 @@ export const cleanupDeletedScreenMenuAssignments = async (
});
}
};
// 그룹 복제 완료 후 탭 컴포넌트의 screenId 참조 일괄 업데이트
export const updateTabScreenReferences = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const { targetScreenIds, screenIdMap } = req.body;
if (!targetScreenIds || !Array.isArray(targetScreenIds)) {
return res.status(400).json({
success: false,
message: "targetScreenIds 배열이 필요합니다.",
});
}
if (!screenIdMap || typeof screenIdMap !== "object") {
return res.status(400).json({
success: false,
message: "screenIdMap 객체가 필요합니다.",
});
}
const result = await screenManagementService.updateTabScreenReferences(
targetScreenIds,
screenIdMap
);
return res.json({
success: true,
message: `${result.updated}개 레이아웃의 탭 참조가 업데이트되었습니다.`,
updated: result.updated,
details: result.details,
});
} catch (error) {
console.error("탭 screenId 참조 업데이트 실패:", error);
return res.status(500).json({
success: false,
message: "탭 screenId 참조 업데이트에 실패했습니다.",
});
}
};
// 화면-메뉴 할당 복제 (다른 회사로 복제 시)
export const copyScreenMenuAssignments = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const { sourceCompanyCode, targetCompanyCode, screenIdMap } = req.body;
const userCompanyCode = req.user?.companyCode;
// 권한 체크: 최고 관리자만 가능
if (userCompanyCode !== "*") {
return res.status(403).json({
success: false,
message: "최고 관리자만 이 기능을 사용할 수 있습니다.",
});
}
if (!sourceCompanyCode || !targetCompanyCode) {
return res.status(400).json({
success: false,
message: "sourceCompanyCode와 targetCompanyCode가 필요합니다.",
});
}
if (!screenIdMap || typeof screenIdMap !== "object") {
return res.status(400).json({
success: false,
message: "screenIdMap 객체가 필요합니다.",
});
}
const result = await screenManagementService.copyScreenMenuAssignments(
sourceCompanyCode,
targetCompanyCode,
screenIdMap
);
return res.json({
success: true,
message: `화면-메뉴 할당 ${result.copiedCount}개 복제 완료`,
data: result,
});
} catch (error) {
console.error("화면-메뉴 할당 복제 실패:", error);
return res.status(500).json({
success: false,
message: "화면-메뉴 할당 복제에 실패했습니다.",
});
}
};
// 코드 카테고리 + 코드 복제
export const copyCodeCategoryAndCodes = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const { sourceCompanyCode, targetCompanyCode } = req.body;
const userCompanyCode = req.user?.companyCode;
if (userCompanyCode !== "*") {
return res.status(403).json({
success: false,
message: "최고 관리자만 이 기능을 사용할 수 있습니다.",
});
}
if (!sourceCompanyCode || !targetCompanyCode) {
return res.status(400).json({
success: false,
message: "sourceCompanyCode와 targetCompanyCode가 필요합니다.",
});
}
const result = await screenManagementService.copyCodeCategoryAndCodes(
sourceCompanyCode,
targetCompanyCode
);
return res.json({
success: true,
message: `코드 카테고리 ${result.copiedCategories}개, 코드 ${result.copiedCodes}개 복제 완료`,
data: result,
});
} catch (error) {
console.error("코드 카테고리/코드 복제 실패:", error);
return res.status(500).json({
success: false,
message: "코드 카테고리/코드 복제에 실패했습니다.",
});
}
};
// 카테고리 매핑 + 값 복제
export const copyCategoryMapping = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const { sourceCompanyCode, targetCompanyCode } = req.body;
const userCompanyCode = req.user?.companyCode;
if (userCompanyCode !== "*") {
return res.status(403).json({
success: false,
message: "최고 관리자만 이 기능을 사용할 수 있습니다.",
});
}
if (!sourceCompanyCode || !targetCompanyCode) {
return res.status(400).json({
success: false,
message: "sourceCompanyCode와 targetCompanyCode가 필요합니다.",
});
}
const result = await screenManagementService.copyCategoryMapping(
sourceCompanyCode,
targetCompanyCode
);
return res.json({
success: true,
message: `카테고리 매핑 ${result.copiedMappings}개, 값 ${result.copiedValues}개 복제 완료`,
data: result,
});
} catch (error) {
console.error("카테고리 매핑/값 복제 실패:", error);
return res.status(500).json({
success: false,
message: "카테고리 매핑/값 복제에 실패했습니다.",
});
}
};
// 테이블 타입관리 입력타입 설정 복제
export const copyTableTypeColumns = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const { sourceCompanyCode, targetCompanyCode } = req.body;
const userCompanyCode = req.user?.companyCode;
if (userCompanyCode !== "*") {
return res.status(403).json({
success: false,
message: "최고 관리자만 이 기능을 사용할 수 있습니다.",
});
}
if (!sourceCompanyCode || !targetCompanyCode) {
return res.status(400).json({
success: false,
message: "sourceCompanyCode와 targetCompanyCode가 필요합니다.",
});
}
const result = await screenManagementService.copyTableTypeColumns(
sourceCompanyCode,
targetCompanyCode
);
return res.json({
success: true,
message: `테이블 타입 컬럼 ${result.copiedCount}개 복제 완료`,
data: result,
});
} catch (error) {
console.error("테이블 타입 컬럼 복제 실패:", error);
return res.status(500).json({
success: false,
message: "테이블 타입 컬럼 복제에 실패했습니다.",
});
}
};
// 연쇄관계 설정 복제
export const copyCascadingRelation = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const { sourceCompanyCode, targetCompanyCode } = req.body;
const userCompanyCode = req.user?.companyCode;
if (userCompanyCode !== "*") {
return res.status(403).json({
success: false,
message: "최고 관리자만 이 기능을 사용할 수 있습니다.",
});
}
if (!sourceCompanyCode || !targetCompanyCode) {
return res.status(400).json({
success: false,
message: "sourceCompanyCode와 targetCompanyCode가 필요합니다.",
});
}
const result = await screenManagementService.copyCascadingRelation(
sourceCompanyCode,
targetCompanyCode
);
return res.json({
success: true,
message: `연쇄관계 설정 ${result.copiedCount}개 복제 완료`,
data: result,
});
} catch (error) {
console.error("연쇄관계 설정 복제 실패:", error);
return res.status(500).json({
success: false,
message: "연쇄관계 설정 복제에 실패했습니다.",
});
}
};