2025-09-01 14:00:31 +09:00
|
|
|
import { Response } from "express";
|
|
|
|
|
import { screenManagementService } from "../services/screenManagementService";
|
|
|
|
|
import { AuthenticatedRequest } from "../types/auth";
|
|
|
|
|
|
|
|
|
|
// 화면 목록 조회
|
|
|
|
|
export const getScreens = async (req: AuthenticatedRequest, res: Response) => {
|
|
|
|
|
try {
|
2025-11-13 12:17:10 +09:00
|
|
|
const userCompanyCode = (req.user as any).companyCode;
|
|
|
|
|
const { page = 1, size = 20, searchTerm, companyCode } = req.query;
|
|
|
|
|
|
|
|
|
|
// 쿼리 파라미터로 companyCode가 전달되면 해당 회사의 화면 조회 (최고 관리자 전용)
|
|
|
|
|
// 아니면 현재 사용자의 companyCode 사용
|
|
|
|
|
const targetCompanyCode = (companyCode as string) || userCompanyCode;
|
|
|
|
|
|
|
|
|
|
// 최고 관리자가 아닌 경우 자신의 회사 코드만 사용 가능
|
|
|
|
|
if (userCompanyCode !== "*" && targetCompanyCode !== userCompanyCode) {
|
|
|
|
|
return res.status(403).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "다른 회사의 화면을 조회할 권한이 없습니다.",
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-09-08 14:20:01 +09:00
|
|
|
|
|
|
|
|
const result = await screenManagementService.getScreensByCompany(
|
2025-11-13 12:17:10 +09:00
|
|
|
targetCompanyCode,
|
2025-09-08 14:20:01 +09:00
|
|
|
parseInt(page as string),
|
2025-11-19 13:22:49 +09:00
|
|
|
parseInt(size as string),
|
|
|
|
|
searchTerm as string // 검색어 전달
|
2025-09-08 14:20:01 +09:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
data: result.data,
|
|
|
|
|
total: result.pagination.total,
|
|
|
|
|
page: result.pagination.page,
|
|
|
|
|
size: result.pagination.size,
|
|
|
|
|
totalPages: result.pagination.totalPages,
|
|
|
|
|
});
|
2025-09-01 14:00:31 +09:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error("화면 목록 조회 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "화면 목록 조회에 실패했습니다." });
|
2025-09-01 11:48:12 +09:00
|
|
|
}
|
2025-09-01 14:00:31 +09:00
|
|
|
};
|
|
|
|
|
|
2025-09-01 18:42:59 +09:00
|
|
|
// 단일 화면 조회
|
|
|
|
|
export const getScreen = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
const screen = await screenManagementService.getScreen(
|
|
|
|
|
parseInt(id),
|
|
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!screen) {
|
|
|
|
|
res.status(404).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "화면을 찾을 수 없습니다.",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.json({ success: true, data: screen });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("화면 조회 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "화면 조회에 실패했습니다." });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-11-11 16:28:17 +09:00
|
|
|
// 화면에 할당된 메뉴 조회
|
|
|
|
|
export const getScreenMenu = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
|
|
|
|
|
const menuInfo = await screenManagementService.getMenuByScreen(
|
|
|
|
|
parseInt(id),
|
|
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
res.json({ success: true, data: menuInfo });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("화면 메뉴 조회 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "화면 메뉴 조회에 실패했습니다." });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-01 14:00:31 +09:00
|
|
|
// 화면 생성
|
|
|
|
|
export const createScreen = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
const screenData = { ...req.body, companyCode };
|
|
|
|
|
const newScreen = await screenManagementService.createScreen(
|
|
|
|
|
screenData,
|
|
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
res.status(201).json({ success: true, data: newScreen });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("화면 생성 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "화면 생성에 실패했습니다." });
|
2025-09-01 11:48:12 +09:00
|
|
|
}
|
2025-09-01 14:00:31 +09:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 화면 수정
|
|
|
|
|
export const updateScreen = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
const updateData = { ...req.body, companyCode };
|
|
|
|
|
const updatedScreen = await screenManagementService.updateScreen(
|
|
|
|
|
parseInt(id),
|
|
|
|
|
updateData,
|
|
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
res.json({ success: true, data: updatedScreen });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("화면 수정 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "화면 수정에 실패했습니다." });
|
2025-09-01 11:48:12 +09:00
|
|
|
}
|
2025-09-01 14:00:31 +09:00
|
|
|
};
|
|
|
|
|
|
2025-10-15 18:31:40 +09:00
|
|
|
// 화면 정보 수정 (메타데이터만)
|
|
|
|
|
export const updateScreenInfo = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
const { companyCode } = req.user as any;
|
2025-12-02 13:20:49 +09:00
|
|
|
const {
|
|
|
|
|
screenName,
|
|
|
|
|
tableName,
|
|
|
|
|
description,
|
|
|
|
|
isActive,
|
|
|
|
|
// REST API 관련 필드 추가
|
|
|
|
|
dataSourceType,
|
|
|
|
|
dbSourceType,
|
|
|
|
|
dbConnectionId,
|
|
|
|
|
restApiConnectionId,
|
|
|
|
|
restApiEndpoint,
|
|
|
|
|
restApiJsonPath,
|
|
|
|
|
} = req.body;
|
|
|
|
|
|
|
|
|
|
console.log("화면 정보 수정 요청:", {
|
|
|
|
|
screenId: id,
|
|
|
|
|
dataSourceType,
|
|
|
|
|
restApiConnectionId,
|
|
|
|
|
restApiEndpoint,
|
|
|
|
|
restApiJsonPath,
|
|
|
|
|
});
|
2025-10-15 18:31:40 +09:00
|
|
|
|
|
|
|
|
await screenManagementService.updateScreenInfo(
|
|
|
|
|
parseInt(id),
|
2025-12-02 13:20:49 +09:00
|
|
|
{
|
|
|
|
|
screenName,
|
|
|
|
|
tableName,
|
|
|
|
|
description,
|
|
|
|
|
isActive,
|
|
|
|
|
dataSourceType,
|
|
|
|
|
dbSourceType,
|
|
|
|
|
dbConnectionId,
|
|
|
|
|
restApiConnectionId,
|
|
|
|
|
restApiEndpoint,
|
|
|
|
|
restApiJsonPath,
|
|
|
|
|
},
|
2025-10-15 18:31:40 +09:00
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
res.json({ success: true, message: "화면 정보가 수정되었습니다." });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("화면 정보 수정 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "화면 정보 수정에 실패했습니다." });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-08 13:10:09 +09:00
|
|
|
// 화면 의존성 체크
|
|
|
|
|
export const checkScreenDependencies = async (
|
2025-09-01 14:00:31 +09:00
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
const { companyCode } = req.user as any;
|
2025-09-08 13:10:09 +09:00
|
|
|
|
|
|
|
|
const result = await screenManagementService.checkScreenDependencies(
|
|
|
|
|
parseInt(id),
|
|
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
res.json({ success: true, ...result });
|
2025-09-01 14:00:31 +09:00
|
|
|
} catch (error) {
|
2025-09-08 13:10:09 +09:00
|
|
|
console.error("화면 의존성 체크 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "의존성 체크에 실패했습니다." });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 화면 삭제 (휴지통으로 이동)
|
|
|
|
|
export const deleteScreen = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
const { companyCode, userId } = req.user as any;
|
|
|
|
|
const { deleteReason, force } = req.body;
|
|
|
|
|
|
|
|
|
|
await screenManagementService.deleteScreen(
|
|
|
|
|
parseInt(id),
|
|
|
|
|
companyCode,
|
|
|
|
|
userId,
|
|
|
|
|
deleteReason,
|
|
|
|
|
force || false
|
|
|
|
|
);
|
|
|
|
|
res.json({ success: true, message: "화면이 휴지통으로 이동되었습니다." });
|
|
|
|
|
} catch (error: any) {
|
2025-09-01 14:00:31 +09:00
|
|
|
console.error("화면 삭제 실패:", error);
|
2025-09-08 13:10:09 +09:00
|
|
|
|
|
|
|
|
// 의존성 오류인 경우 특별 처리
|
|
|
|
|
if (error.code === "SCREEN_HAS_DEPENDENCIES") {
|
|
|
|
|
res.status(409).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: error.message,
|
|
|
|
|
code: error.code,
|
|
|
|
|
dependencies: error.dependencies,
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-01 14:00:31 +09:00
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "화면 삭제에 실패했습니다." });
|
2025-09-01 11:48:12 +09:00
|
|
|
}
|
2025-09-01 14:00:31 +09:00
|
|
|
};
|
|
|
|
|
|
2025-09-08 13:10:09 +09:00
|
|
|
// 화면 복원 (휴지통에서 복원)
|
|
|
|
|
export const restoreScreen = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
const { companyCode, userId } = req.user as any;
|
|
|
|
|
|
|
|
|
|
await screenManagementService.restoreScreen(
|
|
|
|
|
parseInt(id),
|
|
|
|
|
companyCode,
|
|
|
|
|
userId
|
|
|
|
|
);
|
|
|
|
|
res.json({ success: true, message: "화면이 복원되었습니다." });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("화면 복원 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "화면 복원에 실패했습니다." });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 화면 영구 삭제
|
|
|
|
|
export const permanentDeleteScreen = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
|
|
|
|
|
await screenManagementService.permanentDeleteScreen(
|
|
|
|
|
parseInt(id),
|
|
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
res.json({ success: true, message: "화면이 영구적으로 삭제되었습니다." });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("화면 영구 삭제 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "화면 영구 삭제에 실패했습니다." });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 휴지통 화면 목록 조회
|
|
|
|
|
export const getDeletedScreens = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
const page = parseInt(req.query.page as string) || 1;
|
|
|
|
|
const size = parseInt(req.query.size as string) || 20;
|
|
|
|
|
|
|
|
|
|
const result = await screenManagementService.getDeletedScreens(
|
|
|
|
|
companyCode,
|
|
|
|
|
page,
|
|
|
|
|
size
|
|
|
|
|
);
|
|
|
|
|
res.json({ success: true, ...result });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("휴지통 화면 목록 조회 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "휴지통 화면 목록 조회에 실패했습니다.",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 휴지통 화면 일괄 영구 삭제
|
|
|
|
|
export const bulkPermanentDeleteScreens = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
const { screenIds } = req.body;
|
|
|
|
|
|
|
|
|
|
if (!Array.isArray(screenIds) || screenIds.length === 0) {
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "삭제할 화면 ID 목록이 필요합니다.",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const result = await screenManagementService.bulkPermanentDeleteScreens(
|
|
|
|
|
screenIds,
|
|
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let message = `${result.deletedCount}개 화면이 영구 삭제되었습니다.`;
|
|
|
|
|
if (result.skippedCount > 0) {
|
|
|
|
|
message += ` (${result.skippedCount}개 화면은 삭제되지 않았습니다.)`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
message,
|
|
|
|
|
result: {
|
|
|
|
|
deletedCount: result.deletedCount,
|
|
|
|
|
skippedCount: result.skippedCount,
|
|
|
|
|
errors: result.errors,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("휴지통 화면 일괄 삭제 실패:", error);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "일괄 삭제에 실패했습니다.",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-11-13 12:17:10 +09:00
|
|
|
// 연결된 모달 화면 감지 (화면 복사 전 확인)
|
|
|
|
|
export const detectLinkedScreens = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
|
|
|
|
|
const linkedScreens = await screenManagementService.detectLinkedModalScreens(
|
|
|
|
|
parseInt(id)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
data: linkedScreens,
|
|
|
|
|
message: linkedScreens.length > 0
|
|
|
|
|
? `${linkedScreens.length}개의 연결된 모달 화면을 감지했습니다.`
|
|
|
|
|
: "연결된 모달 화면이 없습니다.",
|
|
|
|
|
});
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
console.error("연결된 화면 감지 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: error.message || "연결된 화면 감지에 실패했습니다.",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 화면명 중복 체크
|
|
|
|
|
export const checkDuplicateScreenName = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> => {
|
|
|
|
|
try {
|
|
|
|
|
const { companyCode, screenName } = req.body;
|
|
|
|
|
|
|
|
|
|
if (!companyCode || !screenName) {
|
|
|
|
|
res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "companyCode와 screenName은 필수입니다.",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const isDuplicate =
|
|
|
|
|
await screenManagementService.checkDuplicateScreenName(
|
|
|
|
|
companyCode,
|
|
|
|
|
screenName
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
data: { isDuplicate },
|
|
|
|
|
message: isDuplicate
|
|
|
|
|
? "이미 존재하는 화면명입니다."
|
|
|
|
|
: "사용 가능한 화면명입니다.",
|
|
|
|
|
});
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
console.error("화면명 중복 체크 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: error.message || "화면명 중복 체크에 실패했습니다.",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 화면 일괄 복사 (메인 + 모달 화면들)
|
|
|
|
|
export const copyScreenWithModals = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
const { mainScreen, modalScreens, targetCompanyCode } = req.body;
|
|
|
|
|
const { companyCode, userId } = req.user as any;
|
|
|
|
|
|
|
|
|
|
if (!mainScreen || !mainScreen.screenName || !mainScreen.screenCode) {
|
|
|
|
|
res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "메인 화면 정보(screenName, screenCode)가 필요합니다.",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const result = await screenManagementService.copyScreenWithModals({
|
|
|
|
|
sourceScreenId: parseInt(id),
|
|
|
|
|
companyCode,
|
|
|
|
|
userId,
|
|
|
|
|
targetCompanyCode, // 최고 관리자가 다른 회사로 복사할 때 사용
|
|
|
|
|
mainScreen: {
|
|
|
|
|
screenName: mainScreen.screenName,
|
|
|
|
|
screenCode: mainScreen.screenCode,
|
|
|
|
|
description: mainScreen.description,
|
|
|
|
|
},
|
|
|
|
|
modalScreens: modalScreens || [],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
data: result,
|
|
|
|
|
message: `화면 복사가 완료되었습니다. (메인 1개 + 모달 ${result.modalScreens.length}개)`,
|
|
|
|
|
});
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
console.error("화면 일괄 복사 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: error.message || "화면 일괄 복사에 실패했습니다.",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 화면 복사 (단일 - 하위 호환용)
|
2025-09-03 18:23:47 +09:00
|
|
|
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 || "화면 복사에 실패했습니다.",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-02 11:16:40 +09:00
|
|
|
// 테이블 목록 조회 (모든 테이블)
|
2025-09-01 14:00:31 +09:00
|
|
|
export const getTables = async (req: AuthenticatedRequest, res: Response) => {
|
|
|
|
|
try {
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
const tables = await screenManagementService.getTables(companyCode);
|
|
|
|
|
res.json({ success: true, data: tables });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("테이블 목록 조회 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "테이블 목록 조회에 실패했습니다." });
|
2025-09-01 11:48:12 +09:00
|
|
|
}
|
2025-09-01 14:00:31 +09:00
|
|
|
};
|
|
|
|
|
|
2025-09-02 11:16:40 +09:00
|
|
|
// 특정 테이블 정보 조회 (최적화된 단일 테이블 조회)
|
|
|
|
|
export const getTableInfo = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> => {
|
|
|
|
|
try {
|
|
|
|
|
const { tableName } = req.params;
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
|
|
|
|
|
if (!tableName) {
|
|
|
|
|
res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "테이블명이 필요합니다.",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const tableInfo = await screenManagementService.getTableInfo(
|
|
|
|
|
tableName,
|
|
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!tableInfo) {
|
|
|
|
|
res.status(404).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: `테이블 '${tableName}'을 찾을 수 없습니다.`,
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.json({ success: true, data: tableInfo });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("테이블 정보 조회 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "테이블 정보 조회에 실패했습니다." });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-01 14:00:31 +09:00
|
|
|
// 테이블 컬럼 정보 조회
|
|
|
|
|
export const getTableColumns = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { tableName } = req.params;
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
const columns = await screenManagementService.getTableColumns(
|
|
|
|
|
tableName,
|
|
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
res.json({ success: true, data: columns });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("테이블 컬럼 조회 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "테이블 컬럼 조회에 실패했습니다." });
|
2025-09-01 11:48:12 +09:00
|
|
|
}
|
2025-09-01 14:00:31 +09:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 레이아웃 저장
|
|
|
|
|
export const saveLayout = async (req: AuthenticatedRequest, res: Response) => {
|
|
|
|
|
try {
|
|
|
|
|
const { screenId } = req.params;
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
const layoutData = req.body;
|
|
|
|
|
const savedLayout = await screenManagementService.saveLayout(
|
|
|
|
|
parseInt(screenId),
|
|
|
|
|
layoutData,
|
|
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
res.json({ success: true, data: savedLayout });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("레이아웃 저장 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "레이아웃 저장에 실패했습니다." });
|
2025-09-01 11:48:12 +09:00
|
|
|
}
|
2025-09-01 14:00:31 +09:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 레이아웃 조회
|
|
|
|
|
export const getLayout = async (req: AuthenticatedRequest, res: Response) => {
|
|
|
|
|
try {
|
|
|
|
|
const { screenId } = req.params;
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
const layout = await screenManagementService.getLayout(
|
|
|
|
|
parseInt(screenId),
|
|
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
res.json({ success: true, data: layout });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("레이아웃 조회 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "레이아웃 조회에 실패했습니다." });
|
2025-09-01 11:48:12 +09:00
|
|
|
}
|
2025-09-01 14:00:31 +09:00
|
|
|
};
|
2025-09-01 17:57:52 +09:00
|
|
|
|
|
|
|
|
// 화면 코드 자동 생성
|
|
|
|
|
export const generateScreenCode = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { companyCode: paramCompanyCode } = req.params;
|
|
|
|
|
const { companyCode: userCompanyCode } = req.user as any;
|
|
|
|
|
|
|
|
|
|
// 사용자의 회사 코드 또는 파라미터의 회사 코드 사용
|
|
|
|
|
const targetCompanyCode = paramCompanyCode || userCompanyCode;
|
|
|
|
|
|
|
|
|
|
const generatedCode =
|
|
|
|
|
await screenManagementService.generateScreenCode(targetCompanyCode);
|
|
|
|
|
res.json({ success: true, data: { screenCode: generatedCode } });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("화면 코드 생성 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "화면 코드 생성에 실패했습니다." });
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-09-01 18:42:59 +09:00
|
|
|
|
2025-11-13 12:17:10 +09:00
|
|
|
// 여러 개의 화면 코드 일괄 생성
|
|
|
|
|
export const generateMultipleScreenCodes = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { companyCode, count } = req.body;
|
|
|
|
|
|
|
|
|
|
if (!companyCode || typeof companyCode !== "string") {
|
|
|
|
|
res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "회사 코드(companyCode)는 필수입니다.",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!count || typeof count !== "number" || count < 1 || count > 100) {
|
|
|
|
|
res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "count는 1~100 사이의 숫자여야 합니다.",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const screenCodes =
|
|
|
|
|
await screenManagementService.generateMultipleScreenCodes(
|
|
|
|
|
companyCode,
|
|
|
|
|
count
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
data: { screenCodes },
|
|
|
|
|
message: `${count}개의 화면 코드가 생성되었습니다.`,
|
|
|
|
|
});
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
console.error("화면 코드 일괄 생성 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: error.message || "화면 코드 일괄 생성에 실패했습니다.",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-01 18:42:59 +09:00
|
|
|
// 화면-메뉴 할당
|
|
|
|
|
export const assignScreenToMenu = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { screenId } = req.params;
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
const assignmentData = { ...req.body, companyCode };
|
|
|
|
|
|
|
|
|
|
await screenManagementService.assignScreenToMenu(
|
|
|
|
|
parseInt(screenId),
|
|
|
|
|
assignmentData
|
|
|
|
|
);
|
|
|
|
|
res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
message: "화면이 메뉴에 성공적으로 할당되었습니다.",
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("화면-메뉴 할당 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "화면-메뉴 할당에 실패했습니다." });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 메뉴별 할당된 화면 목록 조회
|
|
|
|
|
export const getScreensByMenu = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { menuObjid } = req.params;
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
|
|
|
|
|
const screens = await screenManagementService.getScreensByMenu(
|
|
|
|
|
parseInt(menuObjid),
|
|
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
res.json({ success: true, data: screens });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("메뉴별 화면 조회 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "메뉴별 화면 조회에 실패했습니다." });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 화면-메뉴 할당 해제
|
|
|
|
|
export const unassignScreenFromMenu = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const { screenId, menuObjid } = req.params;
|
|
|
|
|
const { companyCode } = req.user as any;
|
|
|
|
|
|
|
|
|
|
await screenManagementService.unassignScreenFromMenu(
|
|
|
|
|
parseInt(screenId),
|
|
|
|
|
parseInt(menuObjid),
|
|
|
|
|
companyCode
|
|
|
|
|
);
|
|
|
|
|
res.json({ success: true, message: "화면-메뉴 할당이 해제되었습니다." });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("화면-메뉴 할당 해제 실패:", error);
|
|
|
|
|
res
|
|
|
|
|
.status(500)
|
|
|
|
|
.json({ success: false, message: "화면-메뉴 할당 해제에 실패했습니다." });
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-09-08 13:10:09 +09:00
|
|
|
|
|
|
|
|
// 휴지통 화면들의 메뉴 할당 정리 (관리자용)
|
|
|
|
|
export const cleanupDeletedScreenMenuAssignments = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
const result =
|
|
|
|
|
await screenManagementService.cleanupDeletedScreenMenuAssignments();
|
|
|
|
|
|
|
|
|
|
return res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
message: result.message,
|
|
|
|
|
updatedCount: result.updatedCount,
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("메뉴 할당 정리 실패:", error);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "메뉴 할당 정리에 실패했습니다.",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|