- Integrated express-async-errors to automatically handle errors in async route handlers, enhancing the overall error management in the application. - Updated app.ts to include the express-async-errors import for global error handling. - Removed redundant logging statements in admin and user menu retrieval functions to streamline the code and improve readability. - Adjusted logging levels from info to debug for less critical logs, ensuring that important information is logged appropriately without cluttering the logs.
660 lines
23 KiB
TypeScript
660 lines
23 KiB
TypeScript
import { logger } from "../utils/logger";
|
|
import { query, queryOne } from "../database/db";
|
|
|
|
export class AdminService {
|
|
/**
|
|
* 관리자 메뉴 목록 조회 (회사별 필터링 적용)
|
|
*/
|
|
static async getAdminMenuList(paramMap: any): Promise<any[]> {
|
|
try {
|
|
logger.debug("AdminService.getAdminMenuList 시작");
|
|
|
|
const {
|
|
userId,
|
|
userCompanyCode,
|
|
userType,
|
|
userLang = "ko",
|
|
menuType,
|
|
} = paramMap;
|
|
|
|
// menuType에 따른 WHERE 조건 생성
|
|
const menuTypeCondition =
|
|
menuType !== undefined
|
|
? `MENU.MENU_TYPE = ${parseInt(menuType)}`
|
|
: "1 = 1";
|
|
|
|
// 메뉴 관리 화면인지 좌측 사이드바인지 구분
|
|
// includeInactive가 true거나 menuType이 undefined면 메뉴 관리 화면
|
|
const includeInactive = paramMap.includeInactive === true;
|
|
const isManagementScreen = includeInactive || menuType === undefined;
|
|
// 메뉴 관리 화면: 모든 상태의 메뉴 표시, 좌측 사이드바: active만 표시
|
|
const statusCondition = isManagementScreen
|
|
? "1 = 1"
|
|
: "MENU.STATUS = 'active'";
|
|
const subStatusCondition = isManagementScreen
|
|
? "1 = 1"
|
|
: "MENU_SUB.STATUS = 'active'";
|
|
|
|
// 1. 권한 그룹 기반 필터링 (좌측 사이드바인 경우만)
|
|
let authFilter = "";
|
|
let unionFilter = ""; // UNION ALL의 하위 메뉴 필터
|
|
let queryParams: any[] = [userLang];
|
|
let paramIndex = 2;
|
|
|
|
if (
|
|
menuType !== undefined &&
|
|
userType !== "SUPER_ADMIN" &&
|
|
!isManagementScreen
|
|
) {
|
|
// 좌측 사이드바 + SUPER_ADMIN이 아닌 경우만 권한 체크
|
|
const userRoleGroups = await query<any>(
|
|
`
|
|
SELECT DISTINCT am.objid AS role_objid, am.auth_name
|
|
FROM authority_master am
|
|
JOIN authority_sub_user asu ON am.objid = asu.master_objid
|
|
WHERE asu.user_id = $1
|
|
AND am.status = 'active'
|
|
`,
|
|
[userId]
|
|
);
|
|
|
|
logger.info(
|
|
`✅ 사용자 ${userId}가 속한 권한 그룹: ${userRoleGroups.length}개`,
|
|
{
|
|
roleGroups: userRoleGroups.map((rg: any) => rg.auth_name),
|
|
}
|
|
);
|
|
|
|
// [임시 비활성화] 메뉴 권한 그룹 체크 - 모든 사용자에게 전체 메뉴 표시
|
|
// TODO: 권한 체크 다시 활성화 필요
|
|
logger.info(
|
|
`⚠️ [임시 비활성화] 권한 그룹 체크 스킵 - 사용자 ${userId}(${userType})에게 전체 메뉴 표시`
|
|
);
|
|
|
|
/* [원본 코드 - 권한 그룹 체크]
|
|
if (userType === "COMPANY_ADMIN") {
|
|
// 회사 관리자: 권한 그룹 기반 필터링 적용
|
|
if (userRoleGroups.length > 0) {
|
|
const roleObjids = userRoleGroups.map((rg: any) => rg.role_objid);
|
|
// 회사 관리자도 권한 그룹 설정에 따라 메뉴 필터링
|
|
authFilter = `
|
|
AND MENU.COMPANY_CODE IN ($${paramIndex}, '*')
|
|
AND EXISTS (
|
|
SELECT 1
|
|
FROM rel_menu_auth rma
|
|
WHERE rma.menu_objid = MENU.OBJID
|
|
AND rma.auth_objid = ANY($${paramIndex + 1})
|
|
AND rma.read_yn = 'Y'
|
|
)
|
|
`;
|
|
queryParams.push(userCompanyCode);
|
|
paramIndex++;
|
|
|
|
// 하위 메뉴도 권한 체크
|
|
unionFilter = `
|
|
AND MENU_SUB.COMPANY_CODE IN ($${paramIndex - 1}, '*')
|
|
AND EXISTS (
|
|
SELECT 1
|
|
FROM rel_menu_auth rma
|
|
WHERE rma.menu_objid = MENU_SUB.OBJID
|
|
AND rma.auth_objid = ANY($${paramIndex})
|
|
AND rma.read_yn = 'Y'
|
|
)
|
|
`;
|
|
queryParams.push(roleObjids);
|
|
paramIndex++;
|
|
logger.info(
|
|
`✅ 회사 관리자: 권한 있는 메뉴만 (${roleObjids.length}개 그룹)`
|
|
);
|
|
} else {
|
|
// 권한 그룹이 없는 회사 관리자: 메뉴 없음
|
|
logger.warn(
|
|
`⚠️ 회사 관리자 ${userId}는 권한 그룹이 없어 메뉴가 표시되지 않습니다.`
|
|
);
|
|
return [];
|
|
}
|
|
} else {
|
|
// 일반 사용자: 권한 그룹 필수
|
|
if (userRoleGroups.length > 0) {
|
|
const roleObjids = userRoleGroups.map((rg: any) => rg.role_objid);
|
|
authFilter = `
|
|
AND EXISTS (
|
|
SELECT 1
|
|
FROM rel_menu_auth rma
|
|
WHERE rma.menu_objid = MENU.OBJID
|
|
AND rma.auth_objid = ANY($${paramIndex})
|
|
AND rma.read_yn = 'Y'
|
|
)
|
|
`;
|
|
unionFilter = `
|
|
AND EXISTS (
|
|
SELECT 1
|
|
FROM rel_menu_auth rma
|
|
WHERE rma.menu_objid = MENU_SUB.OBJID
|
|
AND rma.auth_objid = ANY($${paramIndex})
|
|
AND rma.read_yn = 'Y'
|
|
)
|
|
`;
|
|
queryParams.push(roleObjids);
|
|
paramIndex++;
|
|
logger.info(
|
|
`✅ 일반 사용자: 권한 있는 메뉴만 (${roleObjids.length}개 그룹)`
|
|
);
|
|
} else {
|
|
// 권한 그룹이 없는 일반 사용자: 메뉴 없음
|
|
logger.warn(
|
|
`⚠️ 사용자 ${userId}는 권한 그룹이 없어 메뉴가 표시되지 않습니다.`
|
|
);
|
|
return [];
|
|
}
|
|
}
|
|
*/
|
|
} else if (
|
|
menuType !== undefined &&
|
|
userType === "SUPER_ADMIN" &&
|
|
!isManagementScreen
|
|
) {
|
|
// 좌측 사이드바 + SUPER_ADMIN: 권한 그룹 체크 없이 모든 공통 메뉴 표시
|
|
logger.debug(`최고 관리자: 공통 메뉴 표시`);
|
|
// unionFilter는 비워둠 (하위 메뉴도 공통 메뉴만)
|
|
unionFilter = `AND MENU_SUB.COMPANY_CODE = '*'`;
|
|
}
|
|
|
|
// 2. 회사별 필터링 조건 생성
|
|
let companyFilter = "";
|
|
|
|
// SUPER_ADMIN과 COMPANY_ADMIN 구분
|
|
if (userType === "SUPER_ADMIN" && userCompanyCode === "*") {
|
|
// SUPER_ADMIN
|
|
if (isManagementScreen) {
|
|
// 메뉴 관리 화면: 모든 메뉴
|
|
logger.debug("메뉴 관리 화면 (SUPER_ADMIN): 모든 메뉴 표시");
|
|
companyFilter = "";
|
|
} else {
|
|
// 좌측 사이드바: 공통 메뉴만 (company_code = '*')
|
|
logger.debug("좌측 사이드바 (SUPER_ADMIN): 공통 메뉴만 표시");
|
|
companyFilter = `AND MENU.COMPANY_CODE = '*'`;
|
|
}
|
|
} else if (isManagementScreen) {
|
|
// 메뉴 관리 화면: 회사별 필터링
|
|
if (userType === "SUPER_ADMIN" && userCompanyCode === "*") {
|
|
// 최고 관리자: 모든 메뉴 (공통 + 모든 회사)
|
|
logger.debug("메뉴 관리 화면 (SUPER_ADMIN): 모든 메뉴 표시");
|
|
companyFilter = "";
|
|
} else {
|
|
// 회사 관리자: 자기 회사 메뉴만 (공통 메뉴 제외)
|
|
logger.info(
|
|
`✅ 메뉴 관리 화면 (${userType}): 회사 ${userCompanyCode} 메뉴만 표시 (공통 메뉴 제외)`
|
|
);
|
|
companyFilter = `AND MENU.COMPANY_CODE = $${paramIndex}`;
|
|
queryParams.push(userCompanyCode);
|
|
paramIndex++;
|
|
|
|
// 하위 메뉴에도 회사 필터링 적용 (공통 메뉴 제외)
|
|
if (unionFilter === "") {
|
|
unionFilter = `AND MENU_SUB.COMPANY_CODE = $${paramIndex - 1}`;
|
|
}
|
|
}
|
|
} else if (menuType !== undefined) {
|
|
// 좌측 사이드바: authFilter에서 이미 회사 필터링 포함
|
|
// 회사 관리자는 좌측 사이드바에서도 자기 회사 메뉴 조회 가능
|
|
logger.info(
|
|
`✅ 좌측 사이드바: 회사 ${userCompanyCode} 메뉴 표시 (${userType})`
|
|
);
|
|
// companyFilter는 authFilter에서 이미 처리됨
|
|
}
|
|
|
|
// 기존 Java의 selectAdminMenuList 쿼리를 Raw Query로 포팅
|
|
// WITH RECURSIVE 쿼리 구현
|
|
const menuList = await query<any>(
|
|
`
|
|
WITH RECURSIVE v_menu(
|
|
LEVEL,
|
|
MENU_TYPE,
|
|
OBJID,
|
|
PARENT_OBJ_ID,
|
|
MENU_NAME_KOR,
|
|
MENU_URL,
|
|
MENU_DESC,
|
|
SEQ,
|
|
WRITER,
|
|
REGDATE,
|
|
STATUS,
|
|
SYSTEM_NAME,
|
|
COMPANY_CODE,
|
|
LANG_KEY,
|
|
LANG_KEY_DESC,
|
|
PATH,
|
|
CYCLE,
|
|
TRANSLATED_NAME,
|
|
TRANSLATED_DESC
|
|
) AS (
|
|
SELECT
|
|
1 AS LEVEL,
|
|
MENU.MENU_TYPE,
|
|
MENU.OBJID::numeric,
|
|
MENU.PARENT_OBJ_ID,
|
|
MENU.MENU_NAME_KOR,
|
|
MENU.MENU_URL,
|
|
MENU.MENU_DESC,
|
|
MENU.SEQ,
|
|
MENU.WRITER,
|
|
MENU.REGDATE,
|
|
MENU.STATUS,
|
|
MENU.SYSTEM_NAME,
|
|
MENU.COMPANY_CODE,
|
|
MENU.LANG_KEY,
|
|
MENU.LANG_KEY_DESC,
|
|
ARRAY [MENU.OBJID],
|
|
FALSE,
|
|
-- 번역된 메뉴명 (우선순위: 회사별 번역 > 공통 번역 > 기본명)
|
|
COALESCE(
|
|
(SELECT MLT.lang_text
|
|
FROM MULTI_LANG_KEY_MASTER MLKM
|
|
JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id
|
|
WHERE MLKM.lang_key = MENU.LANG_KEY
|
|
AND (MLKM.company_code = MENU.COMPANY_CODE OR (MENU.COMPANY_CODE IS NULL AND MLKM.company_code = '*'))
|
|
AND MLT.lang_code = $1
|
|
LIMIT 1),
|
|
(SELECT MLT.lang_text
|
|
FROM MULTI_LANG_KEY_MASTER MLKM
|
|
JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id
|
|
WHERE MLKM.lang_key = MENU.LANG_KEY
|
|
AND MLKM.company_code = '*'
|
|
AND MLT.lang_code = $1
|
|
LIMIT 1),
|
|
MENU.MENU_NAME_KOR
|
|
),
|
|
-- 번역된 설명 (우선순위: 회사별 번역 > 공통 번역 > 기본명)
|
|
COALESCE(
|
|
(SELECT MLT.lang_text
|
|
FROM MULTI_LANG_KEY_MASTER MLKM
|
|
JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id
|
|
WHERE MLKM.lang_key = MENU.LANG_KEY_DESC
|
|
AND (MLKM.company_code = MENU.COMPANY_CODE OR (MENU.COMPANY_CODE IS NULL AND MLKM.company_code = '*'))
|
|
AND MLT.lang_code = $1
|
|
LIMIT 1),
|
|
(SELECT MLT.lang_text
|
|
FROM MULTI_LANG_KEY_MASTER MLKM
|
|
JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id
|
|
WHERE MLKM.lang_key = MENU.LANG_KEY_DESC
|
|
AND MLKM.company_code = '*'
|
|
AND MLT.lang_code = $1
|
|
LIMIT 1),
|
|
MENU.MENU_DESC
|
|
)
|
|
FROM MENU_INFO MENU
|
|
WHERE ${menuTypeCondition}
|
|
AND ${statusCondition}
|
|
${companyFilter}
|
|
${authFilter}
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM MENU_INFO parent_menu
|
|
WHERE parent_menu.OBJID = MENU.PARENT_OBJ_ID
|
|
)
|
|
|
|
UNION ALL
|
|
|
|
SELECT
|
|
V_MENU.LEVEL + 1,
|
|
MENU_SUB.MENU_TYPE,
|
|
MENU_SUB.OBJID,
|
|
MENU_SUB.PARENT_OBJ_ID,
|
|
MENU_SUB.MENU_NAME_KOR,
|
|
MENU_SUB.MENU_URL,
|
|
MENU_SUB.MENU_DESC,
|
|
MENU_SUB.SEQ,
|
|
MENU_SUB.WRITER,
|
|
MENU_SUB.REGDATE,
|
|
MENU_SUB.STATUS,
|
|
MENU_SUB.SYSTEM_NAME,
|
|
MENU_SUB.COMPANY_CODE,
|
|
MENU_SUB.LANG_KEY,
|
|
MENU_SUB.LANG_KEY_DESC,
|
|
PATH || MENU_SUB.SEQ::numeric,
|
|
MENU_SUB.OBJID = ANY(PATH),
|
|
-- 번역된 메뉴명 (우선순위: 회사별 번역 > 공통 번역 > 기본명)
|
|
COALESCE(
|
|
(SELECT MLT.lang_text
|
|
FROM MULTI_LANG_KEY_MASTER MLKM
|
|
JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id
|
|
WHERE MLKM.lang_key = MENU_SUB.LANG_KEY
|
|
AND (MLKM.company_code = MENU_SUB.COMPANY_CODE OR (MENU_SUB.COMPANY_CODE IS NULL AND MLKM.company_code = '*'))
|
|
AND MLT.lang_code = $1
|
|
LIMIT 1),
|
|
(SELECT MLT.lang_text
|
|
FROM MULTI_LANG_KEY_MASTER MLKM
|
|
JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id
|
|
WHERE MLKM.lang_key = MENU_SUB.LANG_KEY
|
|
AND MLKM.company_code = '*'
|
|
AND MLT.lang_code = $1
|
|
LIMIT 1),
|
|
MENU_SUB.MENU_NAME_KOR
|
|
),
|
|
-- 번역된 설명 (우선순위: 회사별 번역 > 공통 번역 > 기본명)
|
|
COALESCE(
|
|
(SELECT MLT.lang_text
|
|
FROM MULTI_LANG_KEY_MASTER MLKM
|
|
JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id
|
|
WHERE MLKM.lang_key = MENU_SUB.LANG_KEY_DESC
|
|
AND (MLKM.company_code = MENU_SUB.COMPANY_CODE OR (MENU_SUB.COMPANY_CODE IS NULL AND MLKM.company_code = '*'))
|
|
AND MLT.lang_code = $1
|
|
LIMIT 1),
|
|
(SELECT MLT.lang_text
|
|
FROM MULTI_LANG_KEY_MASTER MLKM
|
|
JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id
|
|
WHERE MLKM.lang_key = MENU_SUB.LANG_KEY_DESC
|
|
AND MLKM.company_code = '*'
|
|
AND MLT.lang_code = $1
|
|
LIMIT 1),
|
|
MENU_SUB.MENU_DESC
|
|
)
|
|
FROM MENU_INFO MENU_SUB
|
|
JOIN V_MENU ON MENU_SUB.PARENT_OBJ_ID = V_MENU.OBJID
|
|
WHERE MENU_SUB.OBJID != ANY(V_MENU.PATH)
|
|
AND ${subStatusCondition}
|
|
${unionFilter}
|
|
)
|
|
SELECT
|
|
LEVEL AS LEV,
|
|
CAST(MENU_TYPE AS TEXT) AS MENU_TYPE,
|
|
A.OBJID,
|
|
A.PARENT_OBJ_ID,
|
|
A.MENU_NAME_KOR,
|
|
LPAD(' ', 3 * (LEVEL - 1)) || A.MENU_NAME_KOR AS LPAD_MENU_NAME_KOR,
|
|
A.MENU_URL,
|
|
A.MENU_DESC,
|
|
A.SEQ,
|
|
A.WRITER,
|
|
TO_CHAR(A.REGDATE, 'YYYY-MM-DD') AS REGDATE,
|
|
A.STATUS,
|
|
A.COMPANY_CODE,
|
|
A.LANG_KEY,
|
|
A.LANG_KEY_DESC,
|
|
COALESCE(CM.COMPANY_NAME, '미지정') AS COMPANY_NAME,
|
|
A.TRANSLATED_NAME,
|
|
A.TRANSLATED_DESC,
|
|
CASE UPPER(A.STATUS)
|
|
WHEN 'ACTIVE' THEN '활성화'
|
|
WHEN 'INACTIVE' THEN '비활성화'
|
|
ELSE ''
|
|
END AS STATUS_TITLE
|
|
FROM v_menu A
|
|
LEFT JOIN COMPANY_MNG CM ON A.COMPANY_CODE = CM.COMPANY_CODE
|
|
WHERE 1 = 1
|
|
ORDER BY PATH, SEQ
|
|
`,
|
|
queryParams
|
|
);
|
|
|
|
logger.debug(`관리자 메뉴 목록 조회 결과: ${menuList.length}개`);
|
|
|
|
return menuList;
|
|
} catch (error) {
|
|
logger.error("AdminService.getAdminMenuList 오류:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 사용자 메뉴 목록 조회 (권한 그룹 기반 필터링)
|
|
*/
|
|
static async getUserMenuList(paramMap: any): Promise<any[]> {
|
|
try {
|
|
logger.debug("AdminService.getUserMenuList 시작");
|
|
|
|
const { userId, userCompanyCode, userType, userLang = "ko" } = paramMap;
|
|
|
|
// 1. 권한 그룹 기반 필터링 (SUPER_ADMIN은 제외)
|
|
let authFilter = "";
|
|
let unionFilter = "";
|
|
let queryParams: any[] = [userLang];
|
|
let paramIndex = 2;
|
|
|
|
// [임시 비활성화] 메뉴 권한 그룹 체크 - 모든 사용자에게 전체 메뉴 표시
|
|
// TODO: 권한 체크 다시 활성화 필요
|
|
logger.debug(`getUserMenuList 권한 그룹 체크 스킵 - ${userId}(${userType})`);
|
|
authFilter = "";
|
|
unionFilter = "";
|
|
|
|
/* [원본 코드 - getUserMenuList 권한 그룹 체크]
|
|
if (userType === "SUPER_ADMIN") {
|
|
// SUPER_ADMIN: 권한 그룹 체크 없이 해당 회사의 모든 메뉴 표시
|
|
logger.info(`✅ 좌측 사이드바 (SUPER_ADMIN): 회사 ${userCompanyCode}의 모든 메뉴 표시`);
|
|
authFilter = "";
|
|
unionFilter = "";
|
|
} else {
|
|
// 일반 사용자 / 회사 관리자: 권한 그룹 조회 필요
|
|
const userRoleGroups = await query<any>(
|
|
`
|
|
SELECT DISTINCT am.objid AS role_objid, am.auth_name
|
|
FROM authority_master am
|
|
JOIN authority_sub_user asu ON am.objid = asu.master_objid
|
|
WHERE asu.user_id = $1
|
|
AND am.status = 'active'
|
|
`,
|
|
[userId]
|
|
);
|
|
|
|
logger.info(
|
|
`✅ 사용자 ${userId}가 속한 권한 그룹: ${userRoleGroups.length}개`,
|
|
{
|
|
roleGroups: userRoleGroups.map((rg: any) => rg.auth_name),
|
|
}
|
|
);
|
|
|
|
if (userRoleGroups.length > 0) {
|
|
// 권한 그룹이 있는 경우: read_yn = 'Y'인 메뉴만 필터링
|
|
const roleObjids = userRoleGroups.map((rg: any) => rg.role_objid);
|
|
authFilter = `
|
|
AND EXISTS (
|
|
SELECT 1
|
|
FROM rel_menu_auth rma
|
|
WHERE rma.menu_objid = MENU.OBJID
|
|
AND rma.auth_objid = ANY($${paramIndex})
|
|
AND rma.read_yn = 'Y'
|
|
)
|
|
`;
|
|
unionFilter = `
|
|
AND EXISTS (
|
|
SELECT 1
|
|
FROM rel_menu_auth rma
|
|
WHERE rma.menu_objid = MENU_SUB.OBJID
|
|
AND rma.auth_objid = ANY($${paramIndex})
|
|
AND rma.read_yn = 'Y'
|
|
)
|
|
`;
|
|
queryParams.push(roleObjids);
|
|
paramIndex++;
|
|
logger.info(
|
|
`✅ 권한 그룹 기반 메뉴 필터링 적용: ${roleObjids.length}개 그룹`
|
|
);
|
|
} else {
|
|
// 권한 그룹이 없는 경우: 메뉴 없음
|
|
logger.warn(
|
|
`⚠️ 사용자 ${userId}는 권한 그룹이 없어 메뉴가 표시되지 않습니다.`
|
|
);
|
|
return [];
|
|
}
|
|
}
|
|
*/
|
|
|
|
// 2. 회사별 필터링 조건 생성
|
|
let companyFilter = "";
|
|
|
|
if (userType === "SUPER_ADMIN" && userCompanyCode === "*") {
|
|
// SUPER_ADMIN: 공통 메뉴만 (company_code = '*')
|
|
companyFilter = `AND MENU.COMPANY_CODE = '*'`;
|
|
} else {
|
|
// COMPANY_ADMIN/USER: 자기 회사 메뉴만
|
|
logger.info(
|
|
`✅ 좌측 사이드바 (COMPANY_ADMIN/USER): 회사 ${userCompanyCode} 메뉴만 표시`
|
|
);
|
|
companyFilter = `AND MENU.COMPANY_CODE = $${paramIndex}`;
|
|
queryParams.push(userCompanyCode);
|
|
paramIndex++;
|
|
}
|
|
|
|
// 기존 Java의 selectUserMenuList 쿼리를 Raw Query로 포팅 + 회사별 필터링
|
|
const menuList = await query<any>(
|
|
`
|
|
WITH RECURSIVE v_menu(
|
|
LEVEL,
|
|
MENU_TYPE,
|
|
OBJID,
|
|
PARENT_OBJ_ID,
|
|
MENU_NAME_KOR,
|
|
MENU_URL,
|
|
MENU_DESC,
|
|
SEQ,
|
|
WRITER,
|
|
REGDATE,
|
|
STATUS,
|
|
COMPANY_CODE,
|
|
LANG_KEY,
|
|
LANG_KEY_DESC,
|
|
PATH,
|
|
CYCLE
|
|
) AS (
|
|
SELECT
|
|
1 AS LEVEL,
|
|
MENU_TYPE,
|
|
OBJID::numeric,
|
|
PARENT_OBJ_ID,
|
|
MENU_NAME_KOR,
|
|
MENU_URL,
|
|
MENU_DESC,
|
|
SEQ,
|
|
WRITER,
|
|
REGDATE,
|
|
STATUS,
|
|
COMPANY_CODE,
|
|
LANG_KEY,
|
|
LANG_KEY_DESC,
|
|
ARRAY [MENU.OBJID],
|
|
FALSE
|
|
FROM MENU_INFO MENU
|
|
WHERE PARENT_OBJ_ID = 0
|
|
AND MENU_TYPE = 1
|
|
AND STATUS = 'active'
|
|
${companyFilter}
|
|
${authFilter}
|
|
|
|
UNION ALL
|
|
|
|
SELECT
|
|
V_MENU.LEVEL + 1,
|
|
MENU_SUB.MENU_TYPE,
|
|
MENU_SUB.OBJID,
|
|
MENU_SUB.PARENT_OBJ_ID,
|
|
MENU_SUB.MENU_NAME_KOR,
|
|
MENU_SUB.MENU_URL,
|
|
MENU_SUB.MENU_DESC,
|
|
MENU_SUB.SEQ,
|
|
MENU_SUB.WRITER,
|
|
MENU_SUB.REGDATE,
|
|
MENU_SUB.STATUS,
|
|
MENU_SUB.COMPANY_CODE,
|
|
MENU_SUB.LANG_KEY,
|
|
MENU_SUB.LANG_KEY_DESC,
|
|
PATH || MENU_SUB.SEQ::numeric,
|
|
MENU_SUB.OBJID = ANY(PATH)
|
|
FROM MENU_INFO MENU_SUB
|
|
JOIN V_MENU ON MENU_SUB.PARENT_OBJ_ID = V_MENU.OBJID
|
|
WHERE MENU_SUB.STATUS = 'active'
|
|
${unionFilter}
|
|
)
|
|
SELECT
|
|
LEVEL AS LEV,
|
|
CASE MENU_TYPE
|
|
WHEN '0' THEN 'admin'
|
|
WHEN '1' THEN 'user'
|
|
ELSE ''
|
|
END AS MENU_TYPE,
|
|
A.OBJID,
|
|
A.PARENT_OBJ_ID,
|
|
A.MENU_NAME_KOR,
|
|
LPAD(' ', 3 * (LEVEL - 1)) || A.MENU_NAME_KOR AS LPAD_MENU_NAME_KOR,
|
|
A.MENU_URL,
|
|
A.MENU_DESC,
|
|
A.SEQ,
|
|
A.WRITER,
|
|
TO_CHAR(A.REGDATE, 'YYYY-MM-DD') AS REGDATE,
|
|
A.STATUS,
|
|
A.COMPANY_CODE,
|
|
A.LANG_KEY,
|
|
A.LANG_KEY_DESC,
|
|
COALESCE(CM.COMPANY_NAME, '미지정') AS COMPANY_NAME,
|
|
-- 번역된 메뉴명 (우선순위: 번역 > 기본명)
|
|
COALESCE(MLT_NAME.lang_text, A.MENU_NAME_KOR) AS TRANSLATED_NAME,
|
|
-- 번역된 설명 (우선순위: 번역 > 기본명)
|
|
COALESCE(MLT_DESC.lang_text, A.MENU_DESC) AS TRANSLATED_DESC,
|
|
CASE UPPER(A.STATUS)
|
|
WHEN 'ACTIVE' THEN '활성화'
|
|
WHEN 'INACTIVE' THEN '비활성화'
|
|
ELSE ''
|
|
END AS STATUS_TITLE
|
|
FROM v_menu A
|
|
LEFT JOIN COMPANY_MNG CM ON A.COMPANY_CODE = CM.COMPANY_CODE
|
|
LEFT JOIN MULTI_LANG_KEY_MASTER MLKM_NAME ON A.LANG_KEY = MLKM_NAME.lang_key
|
|
LEFT JOIN MULTI_LANG_TEXT MLT_NAME ON MLKM_NAME.key_id = MLT_NAME.key_id AND MLT_NAME.lang_code = $1
|
|
LEFT JOIN MULTI_LANG_KEY_MASTER MLKM_DESC ON A.LANG_KEY_DESC = MLKM_DESC.lang_key
|
|
LEFT JOIN MULTI_LANG_TEXT MLT_DESC ON MLKM_DESC.key_id = MLT_DESC.key_id AND MLT_DESC.lang_code = $1
|
|
WHERE 1 = 1
|
|
ORDER BY PATH, SEQ
|
|
`,
|
|
queryParams
|
|
);
|
|
|
|
logger.debug(`사용자 메뉴 목록 조회 결과: ${menuList.length}개`);
|
|
|
|
return menuList;
|
|
} catch (error) {
|
|
logger.error("AdminService.getUserMenuList 오류:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 메뉴 정보 조회
|
|
*/
|
|
static async getMenuInfo(menuId: string): Promise<any> {
|
|
try {
|
|
logger.info(`AdminService.getMenuInfo 시작 - menuId: ${menuId}`);
|
|
|
|
// Raw Query를 사용한 메뉴 정보 조회 (회사 정보 포함)
|
|
const menuResult = await query<any>(
|
|
`SELECT
|
|
m.*,
|
|
c.company_name
|
|
FROM menu_info m
|
|
LEFT JOIN company_mng c ON m.company_code = c.company_code
|
|
WHERE m.objid = $1::numeric`,
|
|
[menuId]
|
|
);
|
|
|
|
if (!menuResult || menuResult.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
const menuInfo = menuResult[0];
|
|
|
|
// 응답 형식 조정 (기존 형식과 호환성 유지)
|
|
const result = {
|
|
...menuInfo,
|
|
objid: menuInfo.objid?.toString(),
|
|
menu_type: menuInfo.menu_type?.toString(),
|
|
parent_obj_id: menuInfo.parent_obj_id?.toString(),
|
|
seq: menuInfo.seq?.toString(),
|
|
company_name: menuInfo.company_name || "미지정",
|
|
};
|
|
|
|
logger.info("메뉴 정보 조회 결과:", result);
|
|
return result;
|
|
} catch (error) {
|
|
logger.error("AdminService.getMenuInfo 오류:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|