680 lines
24 KiB
TypeScript
680 lines
24 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.info("AdminService.getAdminMenuList 시작 - 파라미터:", paramMap);
|
|
|
|
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.info(`✅ 최고 관리자는 권한 그룹 체크 없이 모든 공통 메뉴 표시`);
|
|
// unionFilter는 비워둠 (하위 메뉴도 공통 메뉴만)
|
|
unionFilter = `AND MENU_SUB.COMPANY_CODE = '*'`;
|
|
}
|
|
|
|
// 2. 회사별 필터링 조건 생성
|
|
let companyFilter = "";
|
|
|
|
// SUPER_ADMIN과 COMPANY_ADMIN 구분
|
|
if (userType === "SUPER_ADMIN" && userCompanyCode === "*") {
|
|
// SUPER_ADMIN
|
|
if (isManagementScreen) {
|
|
// 메뉴 관리 화면: 모든 메뉴
|
|
logger.info("✅ 메뉴 관리 화면 (SUPER_ADMIN): 모든 메뉴 표시");
|
|
companyFilter = "";
|
|
} else {
|
|
// 좌측 사이드바: 공통 메뉴만 (company_code = '*')
|
|
logger.info("✅ 좌측 사이드바 (SUPER_ADMIN): 공통 메뉴만 표시");
|
|
companyFilter = `AND MENU.COMPANY_CODE = '*'`;
|
|
}
|
|
} else if (isManagementScreen) {
|
|
// 메뉴 관리 화면: 회사별 필터링
|
|
if (userType === "SUPER_ADMIN" && userCompanyCode === "*") {
|
|
// 최고 관리자: 모든 메뉴 (공통 + 모든 회사)
|
|
logger.info("✅ 메뉴 관리 화면 (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.info(
|
|
`관리자 메뉴 목록 조회 결과: ${menuList.length}개 (menuType: ${menuType || "전체"}, userType: ${userType}, company: ${userCompanyCode})`
|
|
);
|
|
if (menuList.length > 0) {
|
|
logger.info("첫 번째 메뉴:", {
|
|
objid: menuList[0].objid,
|
|
name: menuList[0].menu_name_kor,
|
|
companyCode: menuList[0].company_code,
|
|
});
|
|
}
|
|
|
|
return menuList;
|
|
} catch (error) {
|
|
logger.error("AdminService.getAdminMenuList 오류:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 사용자 메뉴 목록 조회 (권한 그룹 기반 필터링)
|
|
*/
|
|
static async getUserMenuList(paramMap: any): Promise<any[]> {
|
|
try {
|
|
logger.info("AdminService.getUserMenuList 시작 - 파라미터:", paramMap);
|
|
|
|
const { userId, userCompanyCode, userType, userLang = "ko" } = paramMap;
|
|
|
|
// 1. 권한 그룹 기반 필터링 (SUPER_ADMIN은 제외)
|
|
let authFilter = "";
|
|
let unionFilter = "";
|
|
let queryParams: any[] = [userLang];
|
|
let paramIndex = 2;
|
|
|
|
// [임시 비활성화] 메뉴 권한 그룹 체크 - 모든 사용자에게 전체 메뉴 표시
|
|
// TODO: 권한 체크 다시 활성화 필요
|
|
logger.info(
|
|
`⚠️ [임시 비활성화] 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.info(
|
|
`사용자 메뉴 목록 조회 결과: ${menuList.length}개 (userType: ${userType}, company: ${userCompanyCode})`
|
|
);
|
|
if (menuList.length > 0) {
|
|
logger.info("첫 번째 메뉴:", {
|
|
objid: menuList[0].objid,
|
|
name: menuList[0].menu_name_kor,
|
|
companyCode: menuList[0].company_code,
|
|
});
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|