feat: 카테고리 컴포넌트 메뉴 스코프 전환 완료

 구현 내용:
1. 백엔드 API 추가
   - GET /api/table-management/menu/:menuObjid/category-columns
   - 형제 메뉴들의 테이블에서 카테고리 타입 컬럼 조회
   - menuService.getSiblingMenuObjids() 재사용

2. 프론트엔드 CategoryWidget 수정
   - menuObjid를 props로 받아 CategoryColumnList에 전달
   - effectiveMenuObjid로 props.menuObjid도 처리
   - 선택된 컬럼에 tableName 포함하여 상태 관리

3. CategoryColumnList 수정
   - menuObjid 기반으로 형제 메뉴의 모든 카테고리 컬럼 조회
   - 테이블명+컬럼명 함께 표시
   - onColumnSelect에 tableName 전달

4. 메뉴 네비게이션 수정
   - AppLayout.tsx: 화면 이동 시 menuObjid를 URL 쿼리 파라미터로 전달
   - useMenu.ts: 동일하게 menuObjid 전달
   - page.tsx: 자식 컴포넌트에도 menuObjid 전달

🎯 효과:
- 이제 형제 메뉴들이 서로 다른 테이블을 사용해도 카테고리 공유 가능
- 메뉴 클릭 → 화면 이동 시 자동으로 menuObjid 전달
- 카테고리 위젯이 형제 메뉴의 모든 카테고리 컬럼 표시
This commit is contained in:
kjs
2025-11-11 14:44:22 +09:00
parent 668b45d4ea
commit 23911d3dd8
7 changed files with 218 additions and 82 deletions

View File

@@ -1599,3 +1599,96 @@ export async function toggleLogTable(
res.status(500).json(response);
}
}
/**
* 메뉴의 형제 메뉴들이 사용하는 모든 테이블의 카테고리 타입 컬럼 조회
*
* @route GET /api/table-management/menu/:menuObjid/category-columns
* @description 형제 메뉴들의 화면에서 사용하는 테이블의 input_type='category' 컬럼 조회
*/
export async function getCategoryColumnsByMenu(
req: AuthenticatedRequest,
res: Response
): Promise<void> {
try {
const { menuObjid } = req.params;
const companyCode = req.user?.companyCode;
logger.info("📥 메뉴별 카테고리 컬럼 조회 요청", { menuObjid, companyCode });
if (!menuObjid) {
return res.status(400).json({
success: false,
message: "메뉴 OBJID가 필요합니다.",
});
}
// 1. 형제 메뉴 조회
const { getSiblingMenuObjids } = await import("../services/menuService");
const siblingObjids = await getSiblingMenuObjids(parseInt(menuObjid));
logger.info("✅ 형제 메뉴 조회 완료", { siblingObjids });
// 2. 형제 메뉴들이 사용하는 테이블 조회
const { getPool } = await import("../database/db");
const pool = getPool();
const tablesQuery = `
SELECT DISTINCT table_name
FROM screen_definitions
WHERE menu_objid = ANY($1)
AND company_code = $2
AND table_name IS NOT NULL
`;
const tablesResult = await pool.query(tablesQuery, [siblingObjids, companyCode]);
const tableNames = tablesResult.rows.map((row: any) => row.table_name);
logger.info("✅ 형제 메뉴 테이블 조회 완료", { tableNames });
if (tableNames.length === 0) {
return res.json({
success: true,
data: [],
message: "형제 메뉴에 연결된 테이블이 없습니다.",
});
}
// 3. 테이블들의 카테고리 타입 컬럼 조회
const columnsQuery = `
SELECT
table_name AS "tableName",
column_name AS "columnName",
column_label AS "columnLabel",
input_type AS "inputType"
FROM table_type_columns
WHERE table_name = ANY($1)
AND company_code = $2
AND input_type = 'category'
ORDER BY table_name, column_name
`;
const columnsResult = await pool.query(columnsQuery, [tableNames, companyCode]);
logger.info("✅ 카테고리 컬럼 조회 완료", {
columnCount: columnsResult.rows.length
});
res.json({
success: true,
data: columnsResult.rows,
message: "카테고리 컬럼 조회 성공",
});
} catch (error: any) {
logger.error("❌ 메뉴별 카테고리 컬럼 조회 실패", {
error: error.message,
errorStack: error.stack,
});
res.status(500).json({
success: false,
message: "카테고리 컬럼 조회에 실패했습니다.",
error: error.message,
});
}
}