diff --git a/backend-node/src/routes/dataRoutes.ts b/backend-node/src/routes/dataRoutes.ts index fb0f1518..33413da3 100644 --- a/backend-node/src/routes/dataRoutes.ts +++ b/backend-node/src/routes/dataRoutes.ts @@ -51,21 +51,26 @@ router.get( } } + // 회사 코드 추출 (멀티테넌시 필터링) + const userCompany = req.user?.companyCode; + console.log(`🔗 조인 데이터 조회:`, { leftTable, rightTable, leftColumn, rightColumn, leftValue, + userCompany, }); - // 조인 데이터 조회 + // 조인 데이터 조회 (회사 코드 전달) const result = await dataService.getJoinedData( leftTable as string, rightTable as string, leftColumn as string, rightColumn as string, - leftValue as string + leftValue as string, + userCompany ); if (!result.success) { diff --git a/backend-node/src/services/dataService.ts b/backend-node/src/services/dataService.ts index 462ebb4d..eb69797e 100644 --- a/backend-node/src/services/dataService.ts +++ b/backend-node/src/services/dataService.ts @@ -409,7 +409,8 @@ class DataService { rightTable: string, leftColumn: string, rightColumn: string, - leftValue?: string | number + leftValue?: string | number, + userCompany?: string ): Promise> { try { // 왼쪽 테이블 접근 검증 @@ -425,18 +426,42 @@ class DataService { } let queryText = ` - SELECT r.* + SELECT DISTINCT r.* FROM "${rightTable}" r INNER JOIN "${leftTable}" l ON l."${leftColumn}" = r."${rightColumn}" `; const values: any[] = []; + const whereConditions: string[] = []; + let paramIndex = 1; + + // 좌측 값 필터링 if (leftValue !== undefined && leftValue !== null) { - queryText += ` WHERE l."${leftColumn}" = $1`; + whereConditions.push(`l."${leftColumn}" = $${paramIndex}`); values.push(leftValue); + paramIndex++; } + // 우측 테이블 회사별 필터링 (company_code 컬럼이 있는 경우) + if (userCompany && userCompany !== "*") { + const hasCompanyCode = await this.checkColumnExists(rightTable, "company_code"); + if (hasCompanyCode) { + whereConditions.push(`r.company_code = $${paramIndex}`); + values.push(userCompany); + paramIndex++; + console.log(`🏢 우측 패널 회사별 필터링 적용: ${rightTable}.company_code = ${userCompany}`); + } + } + + // WHERE 절 추가 + if (whereConditions.length > 0) { + queryText += ` WHERE ${whereConditions.join(" AND ")}`; + } + + console.log("🔍 조인 쿼리 실행:", queryText); + console.log("📊 조인 쿼리 파라미터:", values); + const result = await query(queryText, values); return { diff --git a/frontend/lib/registry/components/split-panel-layout/SplitPanelLayoutComponent.tsx b/frontend/lib/registry/components/split-panel-layout/SplitPanelLayoutComponent.tsx index 3da7ce27..0d6dfbd9 100644 --- a/frontend/lib/registry/components/split-panel-layout/SplitPanelLayoutComponent.tsx +++ b/frontend/lib/registry/components/split-panel-layout/SplitPanelLayoutComponent.tsx @@ -373,10 +373,56 @@ export const SplitPanelLayoutComponent: React.FC const itemId = item.id || item.ID || item[Object.keys(item)[0]] || index; const isSelected = selectedLeftItem && (selectedLeftItem.id === itemId || selectedLeftItem === item); - // 첫 번째 2-3개 필드를 표시 - const keys = Object.keys(item).filter((k) => k !== "id" && k !== "ID"); - const displayTitle = item[keys[0]] || item.name || item.title || `항목 ${index + 1}`; - const displaySubtitle = keys[1] ? item[keys[1]] : null; + + // 조인에 사용하는 leftColumn을 필수로 표시 + const leftColumn = componentConfig.rightPanel?.relation?.leftColumn; + let displayFields: { label: string; value: any }[] = []; + + // 디버그 로그 + if (index === 0) { + console.log("🔍 좌측 패널 표시 로직:"); + console.log(" - leftColumn (조인 키):", leftColumn); + console.log(" - item keys:", Object.keys(item)); + } + + if (leftColumn) { + // 조인 모드: leftColumn 값을 첫 번째로 표시 (필수) + displayFields.push({ + label: leftColumn, + value: item[leftColumn], + }); + + // 추가로 다른 의미있는 필드 1-2개 표시 (name, title 등) + const additionalKeys = Object.keys(item).filter( + (k) => k !== "id" && k !== "ID" && k !== leftColumn && + (k.includes("name") || k.includes("title") || k.includes("desc")) + ); + + if (additionalKeys.length > 0) { + displayFields.push({ + label: additionalKeys[0], + value: item[additionalKeys[0]], + }); + } + + if (index === 0) { + console.log(" ✅ 조인 키 기반 표시:", displayFields); + } + } else { + // 상세 모드 또는 설정 없음: 자동으로 첫 2개 필드 표시 + const keys = Object.keys(item).filter((k) => k !== "id" && k !== "ID"); + displayFields = keys.slice(0, 2).map((key) => ({ + label: key, + value: item[key], + })); + + if (index === 0) { + console.log(" ⚠️ 조인 키 없음, 자동 선택:", displayFields); + } + } + + const displayTitle = displayFields[0]?.value || item.name || item.title || `항목 ${index + 1}`; + const displaySubtitle = displayFields[1]?.value || null; return (
updateLeftPanel({ showAdd: checked })} />
+ {/* 우측 패널 설정 */}