feat: 채번 규칙 및 코드 메뉴별 격리 구현
**주요 변경사항:** 1. **메뉴 스코프 변경 (getSiblingMenuObjids)** - 기존: 형제 메뉴 + 모든 형제의 자식 메뉴 포함 - 변경: 자신 + 자신의 자식 메뉴만 포함 - 결과: 각 2레벨 메뉴가 완전히 독립적으로 격리됨 2. **채번 규칙 메뉴 선택 상태 유지** - useState 초기값 함수에서 저장된 selectedMenuObjid 복원 - 속성창 닫았다 열어도 선택한 메뉴와 채번 규칙 유지 - config.autoGeneration.selectedMenuObjid에 저장 3. **로그 정리** - 프론트엔드: 디버깅 로그 제거 - 백엔드: info 레벨 로그를 debug 레벨로 변경 - 운영 환경에서 불필요한 로그 출력 최소화 **영향:** - 영업관리 메뉴: 영업관리의 채번 규칙/코드만 조회 - 기준정보 메뉴: 기준정보의 채번 규칙/코드만 조회 - 각 메뉴 그룹이 독립적으로 데이터 관리 가능
This commit is contained in:
@@ -8,71 +8,59 @@ import { logger } from "../utils/logger";
|
||||
*/
|
||||
|
||||
/**
|
||||
* 메뉴의 형제 메뉴 OBJID 목록 조회
|
||||
* (같은 부모를 가진 메뉴들)
|
||||
* 메뉴의 형제 메뉴 및 자식 메뉴 OBJID 목록 조회
|
||||
* (같은 부모를 가진 메뉴들 + 자식 메뉴들)
|
||||
*
|
||||
* 메뉴 스코프 규칙:
|
||||
* - 같은 부모를 가진 형제 메뉴들은 카테고리/채번규칙을 공유
|
||||
* - 자식 메뉴의 데이터도 부모 메뉴에서 조회 가능 (3레벨까지만 존재)
|
||||
* - 최상위 메뉴(parent_obj_id = 0)는 자기 자신만 반환
|
||||
* - 메뉴를 찾을 수 없으면 안전하게 자기 자신만 반환
|
||||
*
|
||||
* @param menuObjid 현재 메뉴의 OBJID
|
||||
* @returns 형제 메뉴 OBJID 배열 (자기 자신 포함, 정렬됨)
|
||||
* @returns 형제 메뉴 + 자식 메뉴 OBJID 배열 (자기 자신 포함, 정렬됨)
|
||||
*
|
||||
* @example
|
||||
* // 영업관리 (200)
|
||||
* // ├── 고객관리 (201)
|
||||
* // │ └── 고객등록 (211)
|
||||
* // ├── 계약관리 (202)
|
||||
* // └── 주문관리 (203)
|
||||
*
|
||||
* await getSiblingMenuObjids(201);
|
||||
* // 결과: [201, 202, 203] - 모두 같은 부모(200)를 가진 형제
|
||||
* // 결과: [201, 202, 203, 211] - 형제(202, 203) + 자식(211)
|
||||
*/
|
||||
export async function getSiblingMenuObjids(menuObjid: number): Promise<number[]> {
|
||||
const pool = getPool();
|
||||
|
||||
try {
|
||||
logger.info("형제 메뉴 조회 시작", { menuObjid });
|
||||
logger.debug("메뉴 스코프 조회 시작", { menuObjid });
|
||||
|
||||
// 1. 현재 메뉴의 부모 찾기
|
||||
const parentQuery = `
|
||||
SELECT parent_obj_id FROM menu_info WHERE objid = $1
|
||||
`;
|
||||
const parentResult = await pool.query(parentQuery, [menuObjid]);
|
||||
// 1. 현재 메뉴 자신을 포함
|
||||
const menuObjids = [menuObjid];
|
||||
|
||||
if (parentResult.rows.length === 0) {
|
||||
logger.warn("메뉴를 찾을 수 없음, 자기 자신만 반환", { menuObjid });
|
||||
return [menuObjid]; // 메뉴가 없으면 안전하게 자기 자신만 반환
|
||||
}
|
||||
|
||||
const parentObjId = parentResult.rows[0].parent_obj_id;
|
||||
|
||||
if (!parentObjId || parentObjId === 0) {
|
||||
// 최상위 메뉴인 경우 자기 자신만 반환
|
||||
logger.info("최상위 메뉴 (형제 없음)", { menuObjid, parentObjId });
|
||||
return [menuObjid];
|
||||
}
|
||||
|
||||
// 2. 같은 부모를 가진 형제 메뉴들 조회
|
||||
const siblingsQuery = `
|
||||
// 2. 현재 메뉴의 자식 메뉴들 조회
|
||||
const childrenQuery = `
|
||||
SELECT objid FROM menu_info
|
||||
WHERE parent_obj_id = $1
|
||||
WHERE parent_obj_id = $1
|
||||
ORDER BY objid
|
||||
`;
|
||||
const siblingsResult = await pool.query(siblingsQuery, [parentObjId]);
|
||||
const childrenResult = await pool.query(childrenQuery, [menuObjid]);
|
||||
|
||||
const siblingObjids = siblingsResult.rows.map((row) => Number(row.objid));
|
||||
const childObjids = childrenResult.rows.map((row) => Number(row.objid));
|
||||
|
||||
logger.info("형제 메뉴 조회 완료", {
|
||||
menuObjid,
|
||||
parentObjId,
|
||||
siblingCount: siblingObjids.length,
|
||||
siblings: siblingObjids,
|
||||
// 3. 자신 + 자식을 합쳐서 정렬
|
||||
const allObjids = Array.from(new Set([...menuObjids, ...childObjids])).sort((a, b) => a - b);
|
||||
|
||||
logger.debug("메뉴 스코프 조회 완료", {
|
||||
menuObjid,
|
||||
childCount: childObjids.length,
|
||||
totalCount: allObjids.length
|
||||
});
|
||||
|
||||
return siblingObjids;
|
||||
return allObjids;
|
||||
} catch (error: any) {
|
||||
logger.error("형제 메뉴 조회 실패", {
|
||||
logger.error("메뉴 스코프 조회 실패", {
|
||||
menuObjid,
|
||||
error: error.message,
|
||||
stack: error.stack
|
||||
|
||||
@@ -360,7 +360,7 @@ class NumberingRuleService {
|
||||
|
||||
const result = await pool.query(query, params);
|
||||
|
||||
logger.info("✅ 채번 규칙 쿼리 성공", { rowCount: result.rows.length });
|
||||
logger.debug("채번 규칙 쿼리 성공", { ruleCount: result.rows.length });
|
||||
|
||||
// 파트 정보 추가
|
||||
for (const rule of result.rows) {
|
||||
|
||||
@@ -1565,7 +1565,7 @@ export class ScreenManagementService {
|
||||
WHERE sma.screen_id = $1
|
||||
AND sma.company_code = $2
|
||||
AND sma.is_active = 'Y'
|
||||
ORDER BY sma.created_at ASC
|
||||
ORDER BY sma.created_date ASC
|
||||
LIMIT 1`,
|
||||
[screenId, companyCode]
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user