화면 복사기능 구현
This commit is contained in:
@@ -108,6 +108,41 @@ export const deleteScreen = async (
|
||||
}
|
||||
};
|
||||
|
||||
// 화면 복사
|
||||
export const copyScreen = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { screenName, screenCode, description } = req.body;
|
||||
const { companyCode, userId } = req.user as any;
|
||||
|
||||
const copiedScreen = await screenManagementService.copyScreen(
|
||||
parseInt(id),
|
||||
{
|
||||
screenName,
|
||||
screenCode,
|
||||
description,
|
||||
companyCode,
|
||||
createdBy: userId,
|
||||
}
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: copiedScreen,
|
||||
message: "화면이 복사되었습니다.",
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error("화면 복사 실패:", error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: error.message || "화면 복사에 실패했습니다.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 테이블 목록 조회 (모든 테이블)
|
||||
export const getTables = async (req: AuthenticatedRequest, res: Response) => {
|
||||
try {
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
createScreen,
|
||||
updateScreen,
|
||||
deleteScreen,
|
||||
copyScreen,
|
||||
getTables,
|
||||
getTableInfo,
|
||||
getTableColumns,
|
||||
@@ -28,6 +29,7 @@ router.get("/screens/:id", getScreen);
|
||||
router.post("/screens", createScreen);
|
||||
router.put("/screens/:id", updateScreen);
|
||||
router.delete("/screens/:id", deleteScreen);
|
||||
router.post("/screens/:id/copy", copyScreen);
|
||||
|
||||
// 화면 코드 자동 생성
|
||||
router.get("/generate-screen-code/:companyCode", generateScreenCode);
|
||||
|
||||
@@ -14,8 +14,18 @@ import {
|
||||
WebType,
|
||||
WidgetData,
|
||||
} from "../types/screen";
|
||||
|
||||
import { generateId } from "../utils/generateId";
|
||||
|
||||
// 화면 복사 요청 인터페이스
|
||||
interface CopyScreenRequest {
|
||||
screenName: string;
|
||||
screenCode: string;
|
||||
description?: string;
|
||||
companyCode: string;
|
||||
createdBy: string;
|
||||
}
|
||||
|
||||
// 백엔드에서 사용할 테이블 정보 타입
|
||||
interface TableInfo {
|
||||
tableName: string;
|
||||
@@ -968,6 +978,120 @@ export class ScreenManagementService {
|
||||
|
||||
return `${companyCode}_${paddedNumber}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 화면 복사 (화면 정보 + 레이아웃 모두 복사)
|
||||
*/
|
||||
async copyScreen(
|
||||
sourceScreenId: number,
|
||||
copyData: CopyScreenRequest
|
||||
): Promise<ScreenDefinition> {
|
||||
// 트랜잭션으로 처리
|
||||
return await prisma.$transaction(async (tx) => {
|
||||
// 1. 원본 화면 정보 조회
|
||||
const sourceScreen = await tx.screen_definitions.findFirst({
|
||||
where: {
|
||||
screen_id: sourceScreenId,
|
||||
company_code: copyData.companyCode,
|
||||
},
|
||||
});
|
||||
|
||||
if (!sourceScreen) {
|
||||
throw new Error("복사할 화면을 찾을 수 없습니다.");
|
||||
}
|
||||
|
||||
// 2. 화면 코드 중복 체크
|
||||
const existingScreen = await tx.screen_definitions.findFirst({
|
||||
where: {
|
||||
screen_code: copyData.screenCode,
|
||||
company_code: copyData.companyCode,
|
||||
},
|
||||
});
|
||||
|
||||
if (existingScreen) {
|
||||
throw new Error("이미 존재하는 화면 코드입니다.");
|
||||
}
|
||||
|
||||
// 3. 새 화면 생성
|
||||
const newScreen = await tx.screen_definitions.create({
|
||||
data: {
|
||||
screen_code: copyData.screenCode,
|
||||
screen_name: copyData.screenName,
|
||||
description: copyData.description || sourceScreen.description,
|
||||
company_code: copyData.companyCode,
|
||||
table_name: sourceScreen.table_name,
|
||||
is_active: sourceScreen.is_active,
|
||||
created_by: copyData.createdBy,
|
||||
created_date: new Date(),
|
||||
updated_by: copyData.createdBy,
|
||||
updated_date: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
// 4. 원본 화면의 레이아웃 정보 조회
|
||||
const sourceLayouts = await tx.screen_layouts.findMany({
|
||||
where: {
|
||||
screen_id: sourceScreenId,
|
||||
},
|
||||
orderBy: { display_order: "asc" },
|
||||
});
|
||||
|
||||
// 5. 레이아웃이 있다면 복사
|
||||
if (sourceLayouts.length > 0) {
|
||||
try {
|
||||
// ID 매핑 맵 생성
|
||||
const idMapping: { [oldId: string]: string } = {};
|
||||
|
||||
// 새로운 컴포넌트 ID 미리 생성
|
||||
sourceLayouts.forEach((layout) => {
|
||||
idMapping[layout.component_id] = generateId();
|
||||
});
|
||||
|
||||
// 각 레이아웃 컴포넌트 복사
|
||||
for (const sourceLayout of sourceLayouts) {
|
||||
const newComponentId = idMapping[sourceLayout.component_id];
|
||||
const newParentId = sourceLayout.parent_id
|
||||
? idMapping[sourceLayout.parent_id]
|
||||
: null;
|
||||
|
||||
await tx.screen_layouts.create({
|
||||
data: {
|
||||
screen_id: newScreen.screen_id,
|
||||
component_type: sourceLayout.component_type,
|
||||
component_id: newComponentId,
|
||||
parent_id: newParentId,
|
||||
position_x: sourceLayout.position_x,
|
||||
position_y: sourceLayout.position_y,
|
||||
width: sourceLayout.width,
|
||||
height: sourceLayout.height,
|
||||
properties: sourceLayout.properties as any,
|
||||
display_order: sourceLayout.display_order,
|
||||
created_date: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("레이아웃 복사 중 오류:", error);
|
||||
// 레이아웃 복사 실패해도 화면 생성은 유지
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 생성된 화면 정보 반환
|
||||
return {
|
||||
screenId: newScreen.screen_id,
|
||||
screenCode: newScreen.screen_code,
|
||||
screenName: newScreen.screen_name,
|
||||
description: newScreen.description || "",
|
||||
companyCode: newScreen.company_code,
|
||||
tableName: newScreen.table_name,
|
||||
isActive: newScreen.is_active,
|
||||
createdBy: newScreen.created_by || undefined,
|
||||
createdDate: newScreen.created_date,
|
||||
updatedBy: newScreen.updated_by || undefined,
|
||||
updatedDate: newScreen.updated_date,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 서비스 인스턴스 export
|
||||
|
||||
Reference in New Issue
Block a user