feat: Improve entity join handling with enhanced column validation and support for complex keys
- Updated the entityJoinService to include type casting for source and reference columns, ensuring compatibility during joins. - Implemented validation for reference columns in the TableManagementService, allowing automatic fallback to 'id' if the specified reference column does not exist. - Enhanced logging for join configurations to provide better insights during the join setup process. - Transitioned the SplitPanelLayoutComponent to utilize the entityJoinApi for handling single key to composite key transformations, improving data retrieval efficiency. - Added support for displaying null or empty values as "-" in the SplitPanelLayout, enhancing user experience.
This commit is contained in:
@@ -1250,24 +1250,59 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
|
||||
setRightData(filteredData);
|
||||
} else {
|
||||
// 단일키 (하위 호환성)
|
||||
// 단일키 (하위 호환성) → entityJoinApi 사용으로 전환 (entity 조인 컬럼 지원)
|
||||
const leftColumn = componentConfig.rightPanel?.relation?.leftColumn;
|
||||
const rightColumn = componentConfig.rightPanel?.relation?.foreignKey;
|
||||
|
||||
if (leftColumn && rightColumn && leftTable) {
|
||||
const leftValue = leftItem[leftColumn];
|
||||
const joinedData = await dataApi.getJoinedData(
|
||||
leftTable,
|
||||
const { entityJoinApi } = await import("@/lib/api/entityJoin");
|
||||
|
||||
// 단일키를 복합키 형식으로 변환
|
||||
const searchConditions: Record<string, any> = {};
|
||||
searchConditions[rightColumn] = leftValue;
|
||||
|
||||
// Entity 조인 컬럼 추출
|
||||
const rightJoinColumnsLegacy = extractAdditionalJoinColumns(
|
||||
componentConfig.rightPanel?.columns,
|
||||
rightTableName,
|
||||
leftColumn,
|
||||
rightColumn,
|
||||
leftValue,
|
||||
componentConfig.rightPanel?.dataFilter, // 🆕 데이터 필터 전달
|
||||
true, // 🆕 Entity 조인 활성화
|
||||
componentConfig.rightPanel?.columns, // 🆕 표시 컬럼 전달 (item_info.item_name 등)
|
||||
componentConfig.rightPanel?.deduplication, // 🆕 중복 제거 설정 전달
|
||||
);
|
||||
setRightData(joinedData || []); // 모든 관련 레코드 (배열)
|
||||
if (rightJoinColumnsLegacy) {
|
||||
console.log("🔗 [분할패널] 단일키 모드 additionalJoinColumns:", rightJoinColumnsLegacy);
|
||||
}
|
||||
|
||||
const result = await entityJoinApi.getTableDataWithJoins(rightTableName, {
|
||||
search: searchConditions,
|
||||
enableEntityJoin: true,
|
||||
size: 1000,
|
||||
companyCodeOverride: companyCode,
|
||||
additionalJoinColumns: rightJoinColumnsLegacy,
|
||||
});
|
||||
|
||||
let filteredDataLegacy = result.data || [];
|
||||
|
||||
// 데이터 필터 적용
|
||||
const dataFilterLegacy = componentConfig.rightPanel?.dataFilter;
|
||||
if (dataFilterLegacy?.enabled && dataFilterLegacy.conditions?.length > 0) {
|
||||
filteredDataLegacy = filteredDataLegacy.filter((item: any) => {
|
||||
return dataFilterLegacy.conditions.every((cond: any) => {
|
||||
const value = item[cond.column];
|
||||
const condValue = cond.value;
|
||||
switch (cond.operator) {
|
||||
case "equals":
|
||||
return value === condValue;
|
||||
case "notEquals":
|
||||
return value !== condValue;
|
||||
case "contains":
|
||||
return String(value).includes(String(condValue));
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setRightData(filteredDataLegacy || []);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3802,23 +3837,20 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
|
||||
if (rightColumns && rightColumns.length > 0) {
|
||||
// 설정된 컬럼만 표시 (엔티티 조인 컬럼 처리)
|
||||
// 설정된 컬럼은 null/empty여도 항상 표시 (사용자가 명시적으로 설정한 컬럼이므로)
|
||||
const summaryCount = componentConfig.rightPanel?.summaryColumnCount ?? 3;
|
||||
firstValues = rightColumns
|
||||
.slice(0, summaryCount)
|
||||
.map((col) => {
|
||||
// 🆕 엔티티 조인 컬럼 처리 (getEntityJoinValue 사용)
|
||||
const value = getEntityJoinValue(item, col.name);
|
||||
return [col.name, value, col.label] as [string, any, string];
|
||||
})
|
||||
.filter(([_, value]) => value !== null && value !== undefined && value !== "");
|
||||
});
|
||||
|
||||
allValues = rightColumns
|
||||
.map((col) => {
|
||||
// 🆕 엔티티 조인 컬럼 처리 (getEntityJoinValue 사용)
|
||||
const value = getEntityJoinValue(item, col.name);
|
||||
return [col.name, value, col.label] as [string, any, string];
|
||||
})
|
||||
.filter(([_, value]) => value !== null && value !== undefined && value !== "");
|
||||
});
|
||||
} else {
|
||||
// 설정 없으면 모든 컬럼 표시 (기존 로직)
|
||||
const summaryCount = componentConfig.rightPanel?.summaryColumnCount ?? 3;
|
||||
@@ -3851,8 +3883,10 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
const format = colConfig?.format;
|
||||
const boldValue = colConfig?.bold ?? false;
|
||||
|
||||
// 🆕 포맷 적용 (날짜/숫자/카테고리)
|
||||
const displayValue = formatCellValue(key, value, rightCategoryMappings, format);
|
||||
// 🆕 포맷 적용 (날짜/숫자/카테고리) - null/empty는 "-"로 표시
|
||||
const displayValue = (value === null || value === undefined || value === "")
|
||||
? "-"
|
||||
: formatCellValue(key, value, rightCategoryMappings, format);
|
||||
|
||||
const showLabel = componentConfig.rightPanel?.summaryShowLabel ?? true;
|
||||
|
||||
@@ -3929,8 +3963,10 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
const colConfig = rightColumns?.find((c) => c.name === key);
|
||||
const format = colConfig?.format;
|
||||
|
||||
// 🆕 포맷 적용 (날짜/숫자/카테고리)
|
||||
const displayValue = formatCellValue(key, value, rightCategoryMappings, format);
|
||||
// 🆕 포맷 적용 (날짜/숫자/카테고리) - null/empty는 "-"로 표시
|
||||
const displayValue = (value === null || value === undefined || value === "")
|
||||
? "-"
|
||||
: formatCellValue(key, value, rightCategoryMappings, format);
|
||||
|
||||
return (
|
||||
<tr key={key} className="hover:bg-muted">
|
||||
@@ -3993,13 +4029,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
|
||||
return [col.name, value, col.label] as [string, any, string];
|
||||
})
|
||||
.filter(([key, value]) => {
|
||||
const filtered = value === null || value === undefined || value === "";
|
||||
if (filtered) {
|
||||
console.log(` ❌ 필터링됨: "${key}" (값: ${value})`);
|
||||
}
|
||||
return !filtered;
|
||||
});
|
||||
; // 설정된 컬럼은 null/empty여도 항상 표시
|
||||
|
||||
console.log(" ✅ 최종 표시할 항목:", displayEntries.length, "개");
|
||||
} else {
|
||||
@@ -4017,7 +4047,9 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
<div className="text-muted-foreground mb-1 text-xs font-semibold tracking-wide uppercase">
|
||||
{label || getColumnLabel(key)}
|
||||
</div>
|
||||
<div className="text-sm">{String(value)}</div>
|
||||
<div className="text-sm">
|
||||
{(value === null || value === undefined || value === "") ? <span className="text-muted-foreground">-</span> : String(value)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user