2025-08-25 11:07:39 +09:00
|
|
|
import { Request, Response } from "express";
|
|
|
|
|
import { logger } from "../utils/logger";
|
2025-08-21 13:28:49 +09:00
|
|
|
import { AuthenticatedRequest } from "../types/auth";
|
2025-08-25 11:07:39 +09:00
|
|
|
import { ApiResponse } from "../types/common";
|
|
|
|
|
import { Client } from "pg";
|
2025-08-21 09:41:46 +09:00
|
|
|
import { AdminService } from "../services/adminService";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 관리자 메뉴 목록 조회
|
|
|
|
|
*/
|
|
|
|
|
export async function getAdminMenus(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
logger.info("=== 관리자 메뉴 목록 조회 시작 ===");
|
|
|
|
|
|
|
|
|
|
// 현재 로그인한 사용자의 회사 코드와 로케일 가져오기
|
|
|
|
|
const userCompanyCode = req.user?.companyCode || "ILSHIN";
|
|
|
|
|
const userLang = (req.query.userLang as string) || "ko";
|
|
|
|
|
|
|
|
|
|
logger.info(`사용자 회사 코드: ${userCompanyCode}`);
|
|
|
|
|
logger.info(`사용자 로케일: ${userLang}`);
|
|
|
|
|
|
|
|
|
|
const paramMap = {
|
|
|
|
|
userCompanyCode,
|
|
|
|
|
userLang,
|
|
|
|
|
SYSTEM_NAME: "PLM",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const menuList = await AdminService.getAdminMenuList(paramMap);
|
|
|
|
|
|
|
|
|
|
logger.info(`관리자 메뉴 조회 결과: ${menuList.length}개`);
|
|
|
|
|
if (menuList.length > 0) {
|
|
|
|
|
logger.info("첫 번째 메뉴:", menuList[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const response: ApiResponse<any[]> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "관리자 메뉴 목록 조회 성공",
|
|
|
|
|
data: menuList,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("관리자 메뉴 목록 조회 중 오류 발생:", error);
|
|
|
|
|
|
|
|
|
|
const response: ApiResponse<null> = {
|
|
|
|
|
success: false,
|
|
|
|
|
message: "관리자 메뉴 목록 조회 중 오류가 발생했습니다.",
|
|
|
|
|
error: {
|
|
|
|
|
code: "ADMIN_MENU_LIST_ERROR",
|
|
|
|
|
details: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(500).json(response);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 사용자 메뉴 목록 조회
|
|
|
|
|
*/
|
|
|
|
|
export async function getUserMenus(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
logger.info("=== 사용자 메뉴 목록 조회 시작 ===");
|
|
|
|
|
|
|
|
|
|
// 현재 로그인한 사용자의 회사 코드와 로케일 가져오기
|
|
|
|
|
const userCompanyCode = req.user?.companyCode || "ILSHIN";
|
|
|
|
|
const userLang = (req.query.userLang as string) || "ko";
|
|
|
|
|
|
|
|
|
|
logger.info(`사용자 회사 코드: ${userCompanyCode}`);
|
|
|
|
|
logger.info(`사용자 로케일: ${userLang}`);
|
|
|
|
|
|
|
|
|
|
const paramMap = {
|
|
|
|
|
userCompanyCode,
|
|
|
|
|
userLang,
|
|
|
|
|
SYSTEM_NAME: "PLM",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const menuList = await AdminService.getUserMenuList(paramMap);
|
|
|
|
|
|
|
|
|
|
logger.info(`사용자 메뉴 조회 결과: ${menuList.length}개`);
|
|
|
|
|
if (menuList.length > 0) {
|
|
|
|
|
logger.info("첫 번째 메뉴:", menuList[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const response: ApiResponse<any[]> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "사용자 메뉴 목록 조회 성공",
|
|
|
|
|
data: menuList,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("사용자 메뉴 목록 조회 중 오류 발생:", error);
|
|
|
|
|
|
|
|
|
|
const response: ApiResponse<null> = {
|
|
|
|
|
success: false,
|
|
|
|
|
message: "사용자 메뉴 목록 조회 중 오류가 발생했습니다.",
|
|
|
|
|
error: {
|
|
|
|
|
code: "USER_MENU_LIST_ERROR",
|
|
|
|
|
details: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(500).json(response);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 메뉴 정보 조회
|
|
|
|
|
*/
|
|
|
|
|
export async function getMenuInfo(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const { menuId } = req.params;
|
|
|
|
|
logger.info(`=== 메뉴 정보 조회 시작 - menuId: ${menuId} ===`);
|
|
|
|
|
|
|
|
|
|
const menuInfo = await AdminService.getMenuInfo(menuId);
|
|
|
|
|
|
|
|
|
|
if (!menuInfo) {
|
|
|
|
|
const response: ApiResponse<null> = {
|
|
|
|
|
success: false,
|
|
|
|
|
message: "메뉴를 찾을 수 없습니다.",
|
|
|
|
|
error: {
|
|
|
|
|
code: "MENU_NOT_FOUND",
|
|
|
|
|
details: `Menu ID: ${menuId}`,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
res.status(404).json(response);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "메뉴 정보 조회 성공",
|
|
|
|
|
data: menuInfo,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("메뉴 정보 조회 중 오류 발생:", error);
|
|
|
|
|
|
|
|
|
|
const response: ApiResponse<null> = {
|
|
|
|
|
success: false,
|
|
|
|
|
message: "메뉴 정보 조회 중 오류가 발생했습니다.",
|
|
|
|
|
error: {
|
|
|
|
|
code: "MENU_INFO_ERROR",
|
|
|
|
|
details: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(500).json(response);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-21 13:28:49 +09:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* GET /api/admin/users
|
|
|
|
|
* 사용자 목록 조회 API
|
|
|
|
|
* 기존 Java AdminController.getUserList() 포팅
|
|
|
|
|
*/
|
|
|
|
|
export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
|
|
|
|
|
try {
|
|
|
|
|
logger.info("사용자 목록 조회 요청", {
|
|
|
|
|
query: req.query,
|
|
|
|
|
user: req.user,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 임시 더미 데이터 반환 (실제로는 데이터베이스에서 조회)
|
|
|
|
|
const { page = 1, countPerPage = 20 } = req.query;
|
|
|
|
|
|
|
|
|
|
const dummyUsers = [
|
|
|
|
|
{
|
|
|
|
|
userId: "plm_admin",
|
|
|
|
|
userName: "관리자",
|
|
|
|
|
deptName: "IT팀",
|
|
|
|
|
companyCode: "ILSHIN",
|
|
|
|
|
userType: "admin",
|
|
|
|
|
email: "admin@ilshin.com",
|
|
|
|
|
status: "active",
|
|
|
|
|
regDate: "2024-01-15",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
userId: "user001",
|
|
|
|
|
userName: "홍길동",
|
|
|
|
|
deptName: "영업팀",
|
|
|
|
|
companyCode: "ILSHIN",
|
|
|
|
|
userType: "user",
|
|
|
|
|
email: "hong@ilshin.com",
|
|
|
|
|
status: "active",
|
|
|
|
|
regDate: "2024-01-16",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
userId: "user002",
|
|
|
|
|
userName: "김철수",
|
|
|
|
|
deptName: "개발팀",
|
|
|
|
|
companyCode: "ILSHIN",
|
|
|
|
|
userType: "user",
|
|
|
|
|
email: "kim@ilshin.com",
|
|
|
|
|
status: "inactive",
|
|
|
|
|
regDate: "2024-01-17",
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 페이징 처리
|
|
|
|
|
const startIndex = (Number(page) - 1) * Number(countPerPage);
|
|
|
|
|
const endIndex = startIndex + Number(countPerPage);
|
|
|
|
|
const paginatedUsers = dummyUsers.slice(startIndex, endIndex);
|
|
|
|
|
|
|
|
|
|
const response = {
|
|
|
|
|
success: true,
|
|
|
|
|
data: {
|
|
|
|
|
users: paginatedUsers,
|
|
|
|
|
pagination: {
|
|
|
|
|
currentPage: Number(page),
|
|
|
|
|
countPerPage: Number(countPerPage),
|
|
|
|
|
totalCount: dummyUsers.length,
|
|
|
|
|
totalPages: Math.ceil(dummyUsers.length / Number(countPerPage)),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
message: "사용자 목록 조회 성공",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
logger.info("사용자 목록 조회 성공", {
|
|
|
|
|
totalCount: dummyUsers.length,
|
|
|
|
|
returnedCount: paginatedUsers.length,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("사용자 목록 조회 실패", { error });
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "사용자 목록 조회 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-08-21 14:47:07 +09:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* GET /api/admin/user-locale
|
|
|
|
|
* 사용자 로케일 조회 API
|
|
|
|
|
*/
|
|
|
|
|
export const getUserLocale = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
2025-08-25 11:07:39 +09:00
|
|
|
): Promise<void> => {
|
2025-08-21 14:47:07 +09:00
|
|
|
try {
|
|
|
|
|
logger.info("사용자 로케일 조회 요청", {
|
|
|
|
|
query: req.query,
|
|
|
|
|
user: req.user,
|
|
|
|
|
});
|
|
|
|
|
|
2025-08-25 11:07:39 +09:00
|
|
|
if (!req.user?.userId) {
|
|
|
|
|
res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "사용자 정보가 없습니다.",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 데이터베이스에서 사용자 로케일 조회
|
|
|
|
|
const prisma = (await import("../config/database")).default;
|
|
|
|
|
|
|
|
|
|
const userInfo = await prisma.user_info.findFirst({
|
|
|
|
|
where: {
|
|
|
|
|
user_id: req.user.userId,
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
locale: true,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let userLocale = "en"; // 기본값
|
|
|
|
|
|
|
|
|
|
if (userInfo?.locale) {
|
|
|
|
|
userLocale = userInfo.locale;
|
|
|
|
|
logger.info("데이터베이스에서 사용자 로케일 조회 성공", {
|
|
|
|
|
userId: req.user.userId,
|
|
|
|
|
locale: userLocale,
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
logger.info("사용자 로케일이 설정되지 않음, 기본값 사용", {
|
|
|
|
|
userId: req.user.userId,
|
|
|
|
|
defaultLocale: userLocale,
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-08-21 14:47:07 +09:00
|
|
|
|
|
|
|
|
const response = {
|
|
|
|
|
success: true,
|
|
|
|
|
data: userLocale,
|
|
|
|
|
message: "사용자 로케일 조회 성공",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
logger.info("사용자 로케일 조회 성공", {
|
|
|
|
|
userLocale,
|
2025-08-25 11:07:39 +09:00
|
|
|
userId: req.user.userId,
|
|
|
|
|
fromDatabase: !!userInfo?.locale,
|
2025-08-21 14:47:07 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("사용자 로케일 조회 실패", { error });
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "사용자 로케일 조회 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
2025-08-25 11:07:39 +09:00
|
|
|
* 사용자 로케일 설정
|
|
|
|
|
*/
|
|
|
|
|
export const setUserLocale = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> => {
|
|
|
|
|
try {
|
|
|
|
|
logger.info("사용자 로케일 설정 요청", {
|
|
|
|
|
body: req.body,
|
|
|
|
|
user: req.user,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!req.user?.userId) {
|
|
|
|
|
res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "사용자 정보가 없습니다.",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { locale } = req.body;
|
|
|
|
|
|
|
|
|
|
if (!locale || !["ko", "en", "ja", "zh"].includes(locale)) {
|
|
|
|
|
res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "유효하지 않은 로케일입니다. (ko, en, ja, zh 중 선택)",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 데이터베이스에 사용자 로케일 저장
|
|
|
|
|
const prisma = (await import("../config/database")).default;
|
|
|
|
|
|
|
|
|
|
await prisma.user_info.update({
|
|
|
|
|
where: {
|
|
|
|
|
user_id: req.user.userId,
|
|
|
|
|
},
|
|
|
|
|
data: {
|
|
|
|
|
locale: locale,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
logger.info("사용자 로케일을 데이터베이스에 저장 완료", {
|
|
|
|
|
locale,
|
|
|
|
|
userId: req.user.userId,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const response = {
|
|
|
|
|
success: true,
|
|
|
|
|
data: locale,
|
|
|
|
|
message: "사용자 로케일 설정 성공",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
logger.info("사용자 로케일 설정 성공", {
|
|
|
|
|
locale,
|
|
|
|
|
userId: req.user.userId,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("사용자 로케일 설정 실패", { error });
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "사용자 로케일 설정 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
2025-08-21 14:47:07 +09:00
|
|
|
* 회사 목록 조회 API
|
|
|
|
|
*/
|
|
|
|
|
export const getCompanyList = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
) => {
|
|
|
|
|
try {
|
|
|
|
|
logger.info("회사 목록 조회 요청", {
|
|
|
|
|
query: req.query,
|
|
|
|
|
user: req.user,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 임시 더미 데이터 반환 (실제로는 데이터베이스에서 조회)
|
|
|
|
|
const dummyCompanies = [
|
|
|
|
|
{
|
|
|
|
|
company_code: "ILSHIN",
|
|
|
|
|
company_name: "일신제강",
|
2025-08-25 11:07:39 +09:00
|
|
|
status: "active",
|
|
|
|
|
writer: "admin",
|
|
|
|
|
regdate: new Date().toISOString(),
|
2025-08-21 14:47:07 +09:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
company_code: "HUTECH",
|
|
|
|
|
company_name: "후테크",
|
2025-08-25 11:07:39 +09:00
|
|
|
status: "active",
|
|
|
|
|
writer: "admin",
|
|
|
|
|
regdate: new Date().toISOString(),
|
2025-08-21 14:47:07 +09:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
company_code: "DAIN",
|
|
|
|
|
company_name: "다인",
|
2025-08-25 11:07:39 +09:00
|
|
|
status: "active",
|
|
|
|
|
writer: "admin",
|
|
|
|
|
regdate: new Date().toISOString(),
|
2025-08-21 14:47:07 +09:00
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
2025-08-25 11:07:39 +09:00
|
|
|
// 프론트엔드에서 기대하는 응답 형식으로 변환
|
2025-08-21 14:47:07 +09:00
|
|
|
const response = {
|
|
|
|
|
success: true,
|
|
|
|
|
data: dummyCompanies,
|
|
|
|
|
message: "회사 목록 조회 성공",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
logger.info("회사 목록 조회 성공", {
|
|
|
|
|
totalCount: dummyCompanies.length,
|
2025-08-25 11:07:39 +09:00
|
|
|
response: response,
|
2025-08-21 14:47:07 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("회사 목록 조회 실패", { error });
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "회사 목록 조회 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 다국어 언어 목록 조회 (더미 데이터)
|
|
|
|
|
*/
|
|
|
|
|
export async function getLanguageList(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
logger.info("다국어 언어 목록 조회 요청");
|
|
|
|
|
|
|
|
|
|
// 더미 데이터 반환
|
|
|
|
|
const languages = [
|
|
|
|
|
{
|
|
|
|
|
langCode: "KR",
|
|
|
|
|
langName: "한국어",
|
|
|
|
|
langNative: "한국어",
|
|
|
|
|
isActive: "Y",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
langCode: "EN",
|
|
|
|
|
langName: "English",
|
|
|
|
|
langNative: "English",
|
|
|
|
|
isActive: "Y",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
langCode: "JP",
|
|
|
|
|
langName: "日本語",
|
|
|
|
|
langNative: "日本語",
|
|
|
|
|
isActive: "Y",
|
|
|
|
|
},
|
|
|
|
|
{ langCode: "CN", langName: "中文", langNative: "中文", isActive: "Y" },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const response: ApiResponse<any[]> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "언어 목록 조회 성공",
|
|
|
|
|
data: languages,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("언어 목록 조회 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "언어 목록 조회 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 다국어 키 목록 조회 (더미 데이터)
|
|
|
|
|
*/
|
|
|
|
|
export async function getLangKeyList(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
2025-08-25 11:07:39 +09:00
|
|
|
logger.info("다국어 키 목록 조회 요청", {
|
|
|
|
|
query: req.query,
|
|
|
|
|
user: req.user,
|
|
|
|
|
});
|
2025-08-21 14:47:07 +09:00
|
|
|
|
|
|
|
|
// 더미 데이터 반환
|
|
|
|
|
const langKeys = [
|
|
|
|
|
{
|
|
|
|
|
keyId: 1,
|
|
|
|
|
companyCode: "ILSHIN",
|
|
|
|
|
menuName: "사용자 관리",
|
|
|
|
|
langKey: "user.management.title",
|
|
|
|
|
description: "사용자 관리 페이지 제목",
|
|
|
|
|
isActive: "Y",
|
2025-08-25 11:07:39 +09:00
|
|
|
createdDate: new Date().toISOString(),
|
|
|
|
|
createdBy: "admin",
|
|
|
|
|
updatedDate: new Date().toISOString(),
|
|
|
|
|
updatedBy: "admin",
|
2025-08-21 14:47:07 +09:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
keyId: 2,
|
|
|
|
|
companyCode: "ILSHIN",
|
|
|
|
|
menuName: "메뉴 관리",
|
|
|
|
|
langKey: "menu.management.title",
|
|
|
|
|
description: "메뉴 관리 페이지 제목",
|
|
|
|
|
isActive: "Y",
|
2025-08-25 11:07:39 +09:00
|
|
|
createdDate: new Date().toISOString(),
|
|
|
|
|
createdBy: "admin",
|
|
|
|
|
updatedDate: new Date().toISOString(),
|
|
|
|
|
updatedBy: "admin",
|
2025-08-21 14:47:07 +09:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
keyId: 3,
|
|
|
|
|
companyCode: "HUTECH",
|
|
|
|
|
menuName: "대시보드",
|
|
|
|
|
langKey: "dashboard.title",
|
|
|
|
|
description: "대시보드 페이지 제목",
|
|
|
|
|
isActive: "Y",
|
2025-08-25 11:07:39 +09:00
|
|
|
createdDate: new Date().toISOString(),
|
|
|
|
|
createdBy: "admin",
|
|
|
|
|
updatedDate: new Date().toISOString(),
|
|
|
|
|
updatedBy: "admin",
|
2025-08-21 14:47:07 +09:00
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
2025-08-25 11:07:39 +09:00
|
|
|
// 프론트엔드에서 기대하는 응답 형식으로 변환
|
2025-08-21 14:47:07 +09:00
|
|
|
const response: ApiResponse<any[]> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "다국어 키 목록 조회 성공",
|
|
|
|
|
data: langKeys,
|
|
|
|
|
};
|
|
|
|
|
|
2025-08-25 11:07:39 +09:00
|
|
|
logger.info("다국어 키 목록 조회 성공", {
|
|
|
|
|
totalCount: langKeys.length,
|
|
|
|
|
response: response,
|
|
|
|
|
});
|
|
|
|
|
|
2025-08-21 14:47:07 +09:00
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("다국어 키 목록 조회 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "다국어 키 목록 조회 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 다국어 텍스트 목록 조회 (더미 데이터)
|
|
|
|
|
*/
|
|
|
|
|
export async function getLangTextList(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const { keyId } = req.params;
|
|
|
|
|
logger.info(`다국어 텍스트 목록 조회 요청: keyId = ${keyId}`);
|
|
|
|
|
|
|
|
|
|
// 더미 데이터 반환
|
|
|
|
|
const langTexts = [
|
|
|
|
|
{
|
|
|
|
|
textId: 1,
|
|
|
|
|
keyId: parseInt(keyId),
|
|
|
|
|
langCode: "KR",
|
|
|
|
|
langText: "사용자 관리",
|
|
|
|
|
isActive: "Y",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
textId: 2,
|
|
|
|
|
keyId: parseInt(keyId),
|
|
|
|
|
langCode: "EN",
|
|
|
|
|
langText: "User Management",
|
|
|
|
|
isActive: "Y",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
textId: 3,
|
|
|
|
|
keyId: parseInt(keyId),
|
|
|
|
|
langCode: "JP",
|
|
|
|
|
langText: "ユーザー管理",
|
|
|
|
|
isActive: "Y",
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const response: ApiResponse<any[]> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "다국어 텍스트 목록 조회 성공",
|
|
|
|
|
data: langTexts,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("다국어 텍스트 목록 조회 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "다국어 텍스트 목록 조회 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 다국어 텍스트 저장 (더미 데이터)
|
|
|
|
|
*/
|
|
|
|
|
export async function saveLangTexts(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const { keyId } = req.params;
|
|
|
|
|
const textData = req.body;
|
|
|
|
|
logger.info(`다국어 텍스트 저장 요청: keyId = ${keyId}`, { textData });
|
|
|
|
|
|
|
|
|
|
// 더미 응답
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "다국어 텍스트 저장 성공",
|
|
|
|
|
data: { savedCount: textData.length },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("다국어 텍스트 저장 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "다국어 텍스트 저장 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 다국어 키 저장 (더미 데이터)
|
|
|
|
|
*/
|
|
|
|
|
export async function saveLangKey(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const keyData = req.body;
|
|
|
|
|
logger.info("다국어 키 저장 요청", { keyData });
|
|
|
|
|
|
|
|
|
|
// 더미 응답
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "다국어 키 저장 성공",
|
|
|
|
|
data: { keyId: Math.floor(Math.random() * 1000) + 1 },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("다국어 키 저장 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "다국어 키 저장 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 다국어 키 수정 (더미 데이터)
|
|
|
|
|
*/
|
|
|
|
|
export async function updateLangKey(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const { keyId } = req.params;
|
|
|
|
|
const keyData = req.body;
|
|
|
|
|
logger.info(`다국어 키 수정 요청: keyId = ${keyId}`, { keyData });
|
|
|
|
|
|
|
|
|
|
// 더미 응답
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "다국어 키 수정 성공",
|
|
|
|
|
data: { keyId: parseInt(keyId) },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("다국어 키 수정 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "다국어 키 수정 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 다국어 키 삭제 (더미 데이터)
|
|
|
|
|
*/
|
|
|
|
|
export async function deleteLangKey(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const { keyId } = req.params;
|
|
|
|
|
logger.info(`다국어 키 삭제 요청: keyId = ${keyId}`);
|
|
|
|
|
|
|
|
|
|
// 더미 응답
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "다국어 키 삭제 성공",
|
|
|
|
|
data: { deletedKeyId: parseInt(keyId) },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("다국어 키 삭제 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "다국어 키 삭제 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 다국어 키 상태 토글 (더미 데이터)
|
|
|
|
|
*/
|
|
|
|
|
export async function toggleLangKeyStatus(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const { keyId } = req.params;
|
|
|
|
|
logger.info(`다국어 키 상태 토글 요청: keyId = ${keyId}`);
|
|
|
|
|
|
|
|
|
|
// 더미 응답
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "다국어 키 상태 토글 성공",
|
|
|
|
|
data: "활성화",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("다국어 키 상태 토글 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "다국어 키 상태 토글 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 언어 저장 (더미 데이터)
|
|
|
|
|
*/
|
|
|
|
|
export async function saveLanguage(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const langData = req.body;
|
|
|
|
|
logger.info("언어 저장 요청", { langData });
|
|
|
|
|
|
|
|
|
|
// 더미 응답
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "언어 저장 성공",
|
|
|
|
|
data: { langCode: langData.langCode },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("언어 저장 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "언어 저장 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 언어 수정 (더미 데이터)
|
|
|
|
|
*/
|
|
|
|
|
export async function updateLanguage(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const { langCode } = req.params;
|
|
|
|
|
const langData = req.body;
|
|
|
|
|
logger.info(`언어 수정 요청: langCode = ${langCode}`, { langData });
|
|
|
|
|
|
|
|
|
|
// 더미 응답
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "언어 수정 성공",
|
|
|
|
|
data: { langCode },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("언어 수정 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "언어 수정 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 언어 상태 토글 (더미 데이터)
|
|
|
|
|
*/
|
|
|
|
|
export async function toggleLanguageStatus(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const { langCode } = req.params;
|
|
|
|
|
logger.info(`언어 상태 토글 요청: langCode = ${langCode}`);
|
|
|
|
|
|
|
|
|
|
// 더미 응답
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "언어 상태 토글 성공",
|
|
|
|
|
data: "활성화",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("언어 상태 토글 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "언어 상태 토글 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-25 11:07:39 +09:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 메뉴 저장 (추가/수정)
|
|
|
|
|
*/
|
|
|
|
|
export async function saveMenu(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const menuData = req.body;
|
|
|
|
|
logger.info("메뉴 저장 요청", { menuData, user: req.user });
|
|
|
|
|
|
|
|
|
|
// PostgreSQL 클라이언트 생성
|
|
|
|
|
const client = new Client({
|
|
|
|
|
connectionString:
|
|
|
|
|
process.env.DATABASE_URL ||
|
|
|
|
|
"postgresql://postgres:postgres@localhost:5432/ilshin",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await client.connect();
|
|
|
|
|
|
|
|
|
|
// 실제 데이터베이스에 저장
|
|
|
|
|
const query = `
|
|
|
|
|
INSERT INTO menu_info (
|
|
|
|
|
objid, menu_type, parent_obj_id, menu_name_kor, menu_name_eng,
|
|
|
|
|
seq, menu_url, menu_desc, writer, regdate, status,
|
|
|
|
|
system_name, company_code, lang_key, lang_key_desc
|
|
|
|
|
) VALUES (
|
|
|
|
|
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15
|
|
|
|
|
) RETURNING *
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const values = [
|
|
|
|
|
Date.now(), // objid
|
|
|
|
|
menuData.menuType || null, // menu_type
|
|
|
|
|
menuData.parentObjId || null, // parent_obj_id
|
|
|
|
|
menuData.menuNameKor, // menu_name_kor
|
|
|
|
|
menuData.menuNameEng || null, // menu_name_eng
|
|
|
|
|
menuData.seq || null, // seq
|
|
|
|
|
menuData.menuUrl || null, // menu_url
|
|
|
|
|
menuData.menuDesc || null, // menu_desc
|
|
|
|
|
req.user?.userId || "admin", // writer
|
|
|
|
|
new Date(), // regdate
|
|
|
|
|
menuData.status || "active", // status
|
|
|
|
|
menuData.systemName || "PLM", // system_name
|
|
|
|
|
menuData.companyCode || "*", // company_code
|
|
|
|
|
menuData.langKey || null, // lang_key
|
|
|
|
|
menuData.langKeyDesc || null, // lang_key_desc
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const result = await client.query(query, values);
|
|
|
|
|
const savedMenu = result.rows[0];
|
|
|
|
|
|
|
|
|
|
await client.end();
|
|
|
|
|
|
|
|
|
|
logger.info("메뉴 저장 성공", { savedMenu });
|
|
|
|
|
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "메뉴가 성공적으로 저장되었습니다.",
|
|
|
|
|
data: {
|
|
|
|
|
objid: savedMenu.objid,
|
|
|
|
|
menuNameKor: savedMenu.menu_name_kor,
|
|
|
|
|
menuNameEng: savedMenu.menu_name_eng,
|
|
|
|
|
menuUrl: savedMenu.menu_url,
|
|
|
|
|
menuDesc: savedMenu.menu_desc,
|
|
|
|
|
status: savedMenu.status,
|
|
|
|
|
writer: savedMenu.writer,
|
|
|
|
|
regdate: savedMenu.regdate,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("메뉴 저장 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "메뉴 저장 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 메뉴 수정
|
|
|
|
|
*/
|
|
|
|
|
export async function updateMenu(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const { menuId } = req.params;
|
|
|
|
|
const menuData = req.body;
|
|
|
|
|
logger.info(`메뉴 수정 요청: menuId = ${menuId}`, {
|
|
|
|
|
menuData,
|
|
|
|
|
user: req.user,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// PostgreSQL 클라이언트 생성
|
|
|
|
|
const client = new Client({
|
|
|
|
|
connectionString:
|
|
|
|
|
process.env.DATABASE_URL ||
|
|
|
|
|
"postgresql://postgres:postgres@localhost:5432/ilshin",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await client.connect();
|
|
|
|
|
|
|
|
|
|
// 실제 데이터베이스에서 메뉴 수정
|
|
|
|
|
const query = `
|
|
|
|
|
UPDATE menu_info
|
|
|
|
|
SET
|
|
|
|
|
menu_type = $1,
|
|
|
|
|
parent_obj_id = $2,
|
|
|
|
|
menu_name_kor = $3,
|
|
|
|
|
menu_name_eng = $4,
|
|
|
|
|
seq = $5,
|
|
|
|
|
menu_url = $6,
|
|
|
|
|
menu_desc = $7,
|
|
|
|
|
status = $8,
|
|
|
|
|
system_name = $9,
|
|
|
|
|
company_code = $10,
|
|
|
|
|
lang_key = $11,
|
|
|
|
|
lang_key_desc = $12
|
|
|
|
|
WHERE objid = $13
|
|
|
|
|
RETURNING *
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const values = [
|
|
|
|
|
menuData.menuType ? BigInt(menuData.menuType) : null, // menu_type
|
|
|
|
|
menuData.parentObjId ? BigInt(menuData.parentObjId) : null, // parent_obj_id
|
|
|
|
|
menuData.menuNameKor, // menu_name_kor
|
|
|
|
|
menuData.menuNameEng || null, // menu_name_eng
|
|
|
|
|
menuData.seq ? BigInt(menuData.seq) : null, // seq
|
|
|
|
|
menuData.menuUrl || null, // menu_url
|
|
|
|
|
menuData.menuDesc || null, // menu_desc
|
|
|
|
|
menuData.status || "active", // status
|
|
|
|
|
menuData.systemName || "PLM", // system_name
|
|
|
|
|
menuData.companyCode || "*", // company_code
|
|
|
|
|
menuData.langKey || null, // lang_key
|
|
|
|
|
menuData.langKeyDesc || null, // lang_key_desc
|
|
|
|
|
BigInt(menuId), // objid (WHERE 조건)
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const result = await client.query(query, values);
|
|
|
|
|
|
|
|
|
|
if (result.rowCount === 0) {
|
|
|
|
|
await client.end();
|
|
|
|
|
res.status(404).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "수정할 메뉴를 찾을 수 없습니다.",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const updatedMenu = result.rows[0];
|
|
|
|
|
await client.end();
|
|
|
|
|
|
|
|
|
|
logger.info("메뉴 수정 성공", { updatedMenu });
|
|
|
|
|
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "메뉴가 성공적으로 수정되었습니다.",
|
|
|
|
|
data: {
|
|
|
|
|
objid: updatedMenu.objid.toString(),
|
|
|
|
|
menuNameKor: updatedMenu.menu_name_kor,
|
|
|
|
|
menuNameEng: updatedMenu.menu_name_eng,
|
|
|
|
|
menuUrl: updatedMenu.menu_url,
|
|
|
|
|
menuDesc: updatedMenu.menu_desc,
|
|
|
|
|
status: updatedMenu.status,
|
|
|
|
|
writer: updatedMenu.writer,
|
|
|
|
|
regdate: updatedMenu.regdate,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("메뉴 수정 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "메뉴 수정 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 메뉴 삭제
|
|
|
|
|
*/
|
|
|
|
|
export async function deleteMenu(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const { menuId } = req.params;
|
|
|
|
|
logger.info(`메뉴 삭제 요청: menuId = ${menuId}`, { user: req.user });
|
|
|
|
|
|
|
|
|
|
// PostgreSQL 클라이언트 생성
|
|
|
|
|
const client = new Client({
|
|
|
|
|
connectionString:
|
|
|
|
|
process.env.DATABASE_URL ||
|
|
|
|
|
"postgresql://postgres:postgres@localhost:5432/ilshin",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await client.connect();
|
|
|
|
|
|
|
|
|
|
// 실제 데이터베이스에서 메뉴 삭제
|
|
|
|
|
const query = `
|
|
|
|
|
DELETE FROM menu_info
|
|
|
|
|
WHERE objid = $1
|
|
|
|
|
RETURNING *
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await client.query(query, [BigInt(menuId)]);
|
|
|
|
|
|
|
|
|
|
if (result.rowCount === 0) {
|
|
|
|
|
await client.end();
|
|
|
|
|
res.status(404).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "삭제할 메뉴를 찾을 수 없습니다.",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const deletedMenu = result.rows[0];
|
|
|
|
|
await client.end();
|
|
|
|
|
|
|
|
|
|
logger.info("메뉴 삭제 성공", { deletedMenu });
|
|
|
|
|
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "메뉴가 성공적으로 삭제되었습니다.",
|
|
|
|
|
data: {
|
|
|
|
|
objid: deletedMenu.objid.toString(),
|
|
|
|
|
menuNameKor: deletedMenu.menu_name_kor,
|
|
|
|
|
menuNameEng: deletedMenu.menu_name_eng,
|
|
|
|
|
menuUrl: deletedMenu.menu_url,
|
|
|
|
|
menuDesc: deletedMenu.menu_desc,
|
|
|
|
|
status: deletedMenu.status,
|
|
|
|
|
writer: deletedMenu.writer,
|
|
|
|
|
regdate: deletedMenu.regdate,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("메뉴 삭제 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "메뉴 삭제 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 메뉴 일괄 삭제
|
|
|
|
|
*/
|
|
|
|
|
export async function deleteMenusBatch(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const menuIds = req.body as string[];
|
|
|
|
|
logger.info("메뉴 일괄 삭제 요청", { menuIds, user: req.user });
|
|
|
|
|
|
|
|
|
|
if (!Array.isArray(menuIds) || menuIds.length === 0) {
|
|
|
|
|
res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "삭제할 메뉴 ID 목록이 필요합니다.",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PostgreSQL 클라이언트 생성
|
|
|
|
|
const client = new Client({
|
|
|
|
|
connectionString:
|
|
|
|
|
process.env.DATABASE_URL ||
|
|
|
|
|
"postgresql://postgres:postgres@localhost:5432/ilshin",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await client.connect();
|
|
|
|
|
|
|
|
|
|
let deletedCount = 0;
|
|
|
|
|
let failedCount = 0;
|
|
|
|
|
const deletedMenus: any[] = [];
|
|
|
|
|
const failedMenuIds: string[] = [];
|
|
|
|
|
|
|
|
|
|
// 각 메뉴 ID에 대해 삭제 시도
|
|
|
|
|
for (const menuId of menuIds) {
|
|
|
|
|
try {
|
|
|
|
|
const query = `
|
|
|
|
|
DELETE FROM menu_info
|
|
|
|
|
WHERE objid = $1
|
|
|
|
|
RETURNING *
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await client.query(query, [BigInt(menuId)]);
|
|
|
|
|
|
|
|
|
|
if (result.rowCount && result.rowCount > 0) {
|
|
|
|
|
deletedCount++;
|
|
|
|
|
deletedMenus.push(result.rows[0]);
|
|
|
|
|
} else {
|
|
|
|
|
failedCount++;
|
|
|
|
|
failedMenuIds.push(menuId);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error(`메뉴 삭제 실패 (ID: ${menuId}):`, error);
|
|
|
|
|
failedCount++;
|
|
|
|
|
failedMenuIds.push(menuId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await client.end();
|
|
|
|
|
|
|
|
|
|
logger.info("메뉴 일괄 삭제 완료", {
|
|
|
|
|
total: menuIds.length,
|
|
|
|
|
deletedCount,
|
|
|
|
|
failedCount,
|
|
|
|
|
deletedMenus,
|
|
|
|
|
failedMenuIds,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: `메뉴 일괄 삭제 완료: ${deletedCount}개 삭제, ${failedCount}개 실패`,
|
|
|
|
|
data: {
|
|
|
|
|
deletedCount,
|
|
|
|
|
failedCount,
|
|
|
|
|
total: menuIds.length,
|
|
|
|
|
deletedMenus,
|
|
|
|
|
failedMenuIds,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("메뉴 일괄 삭제 실패:", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "메뉴 일괄 삭제 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 회사 목록 조회 (실제 데이터베이스에서)
|
|
|
|
|
*/
|
|
|
|
|
export async function getCompanyListFromDB(
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
logger.info("회사 목록 조회 요청 (DB)", { user: req.user });
|
|
|
|
|
|
|
|
|
|
// PostgreSQL 클라이언트 생성
|
|
|
|
|
const client = new Client({
|
|
|
|
|
connectionString:
|
|
|
|
|
process.env.DATABASE_URL ||
|
|
|
|
|
"postgresql://postgres:postgres@localhost:5432/ilshin",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await client.connect();
|
|
|
|
|
|
|
|
|
|
// company_mng 테이블에서 회사 목록 조회
|
|
|
|
|
const query = `
|
|
|
|
|
SELECT
|
|
|
|
|
company_code,
|
|
|
|
|
company_name,
|
|
|
|
|
writer,
|
|
|
|
|
regdate,
|
|
|
|
|
status
|
|
|
|
|
FROM company_mng
|
|
|
|
|
ORDER BY regdate DESC
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await client.query(query);
|
|
|
|
|
const companies = result.rows;
|
|
|
|
|
|
|
|
|
|
await client.end();
|
|
|
|
|
|
|
|
|
|
logger.info("회사 목록 조회 성공 (DB)", { count: companies.length });
|
|
|
|
|
|
|
|
|
|
const response: ApiResponse<any> = {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "회사 목록 조회 성공",
|
|
|
|
|
data: companies,
|
|
|
|
|
total: companies.length,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json(response);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("회사 목록 조회 실패 (DB):", error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "회사 목록 조회 중 오류가 발생했습니다.",
|
|
|
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|