feat: 화면 서브 테이블 정보 조회 기능 추가

- 화면 그룹에 대한 서브 테이블 관계를 조회하는 API 및 라우트 구현
- 화면 그룹 목록에서 서브 테이블 정보를 포함하여 데이터 흐름을 시각화
- 프론트엔드에서 화면 선택 시 그룹 및 서브 테이블 정보 연동 기능 추가
- 화면 노드 및 관계 시각화 컴포넌트에 서브 테이블 정보 통합
This commit is contained in:
DDD1542
2026-01-05 18:18:26 +09:00
parent 7caf2dea94
commit 6925e3af3f
10 changed files with 2012 additions and 158 deletions

View File

@@ -39,11 +39,25 @@ export const getScreenGroups = async (req: Request, res: Response) => {
const countResult = await pool.query(countQuery, params);
const total = parseInt(countResult.rows[0].total);
// 데이터 조회
// 데이터 조회 (screens 배열 포함)
const dataQuery = `
SELECT
sg.*,
(SELECT COUNT(*) FROM screen_group_screens sgs WHERE sgs.group_id = sg.id) as screen_count
(SELECT COUNT(*) FROM screen_group_screens sgs WHERE sgs.group_id = sg.id) as screen_count,
(SELECT json_agg(
json_build_object(
'id', sgs.id,
'screen_id', sgs.screen_id,
'screen_name', sd.screen_name,
'screen_role', sgs.screen_role,
'display_order', sgs.display_order,
'is_default', sgs.is_default,
'table_name', sd.table_name
) ORDER BY sgs.display_order
) FROM screen_group_screens sgs
LEFT JOIN screen_definitions sd ON sgs.screen_id = sd.screen_id
WHERE sgs.group_id = sg.id
) as screens
FROM screen_groups sg
${whereClause}
ORDER BY sg.display_order ASC, sg.created_date DESC
@@ -84,7 +98,8 @@ export const getScreenGroup = async (req: Request, res: Response) => {
'screen_name', sd.screen_name,
'screen_role', sgs.screen_role,
'display_order', sgs.display_order,
'is_default', sgs.is_default
'is_default', sgs.is_default,
'table_name', sd.table_name
) ORDER BY sgs.display_order
) FROM screen_group_screens sgs
LEFT JOIN screen_definitions sd ON sgs.screen_id = sd.screen_id
@@ -981,3 +996,109 @@ export const getMultipleScreenLayoutSummary = async (req: Request, res: Response
}
};
// ============================================================
// 화면 서브 테이블 관계 조회 (조인/참조 테이블)
// ============================================================
// 여러 화면의 서브 테이블 정보 조회 (메인 테이블 → 서브 테이블 관계)
export const getScreenSubTables = async (req: Request, res: Response) => {
try {
const { screenIds } = req.body;
if (!screenIds || !Array.isArray(screenIds) || screenIds.length === 0) {
return res.status(400).json({ success: false, message: "screenIds 배열이 필요합니다." });
}
// 화면별 메인 테이블과 서브 테이블 관계 조회
// componentConfig에서 tableName, sourceTable 추출
const query = `
SELECT DISTINCT
sd.screen_id,
sd.screen_name,
sd.table_name as main_table,
COALESCE(
sl.properties->'componentConfig'->>'tableName',
sl.properties->'componentConfig'->>'sourceTable'
) as sub_table,
sl.properties->>'componentType' as component_type,
sl.properties->'componentConfig'->>'targetTable' as target_table
FROM screen_definitions sd
JOIN screen_layouts sl ON sd.screen_id = sl.screen_id
WHERE sd.screen_id = ANY($1)
AND (
sl.properties->'componentConfig'->>'tableName' IS NOT NULL
OR sl.properties->'componentConfig'->>'sourceTable' IS NOT NULL
)
ORDER BY sd.screen_id
`;
const result = await pool.query(query, [screenIds]);
// 화면별 서브 테이블 그룹화
const screenSubTables: Record<number, {
screenId: number;
screenName: string;
mainTable: string;
subTables: Array<{
tableName: string;
componentType: string;
relationType: string; // 'join' | 'lookup' | 'source'
}>;
}> = {};
result.rows.forEach((row: any) => {
const screenId = row.screen_id;
const mainTable = row.main_table;
const subTable = row.sub_table;
// 메인 테이블과 동일한 경우 제외
if (!subTable || subTable === mainTable) {
return;
}
if (!screenSubTables[screenId]) {
screenSubTables[screenId] = {
screenId,
screenName: row.screen_name,
mainTable: mainTable || '',
subTables: [],
};
}
// 중복 체크
const exists = screenSubTables[screenId].subTables.some(
(st) => st.tableName === subTable
);
if (!exists) {
// 관계 타입 추론
let relationType = 'lookup';
const componentType = row.component_type || '';
if (componentType.includes('autocomplete') || componentType.includes('entity-search')) {
relationType = 'lookup';
} else if (componentType.includes('modal-repeater') || componentType.includes('selected-items')) {
relationType = 'source';
} else if (componentType.includes('table')) {
relationType = 'join';
}
screenSubTables[screenId].subTables.push({
tableName: subTable,
componentType: componentType,
relationType: relationType,
});
}
});
logger.info("화면 서브 테이블 정보 조회", { screenIds, resultCount: Object.keys(screenSubTables).length });
res.json({
success: true,
data: screenSubTables,
});
} catch (error: any) {
logger.error("화면 서브 테이블 정보 조회 실패:", error);
res.status(500).json({ success: false, message: "화면 서브 테이블 정보 조회에 실패했습니다.", error: error.message });
}
};