검색필터 분할패널 데이터 합산기능 추가
This commit is contained in:
@@ -34,7 +34,7 @@ import {
|
||||
} from "@/components/ui/dialog";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useTableOptions } from "@/contexts/TableOptionsContext";
|
||||
import { TableFilter, ColumnVisibility } from "@/types/table-options";
|
||||
import { TableFilter, ColumnVisibility, GroupSumConfig } from "@/types/table-options";
|
||||
import { useAuth } from "@/hooks/useAuth";
|
||||
|
||||
export interface SplitPanelLayoutComponentProps extends ComponentRendererProps {
|
||||
@@ -86,16 +86,29 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
if (columnName.includes(".")) {
|
||||
const [tableName, fieldName] = columnName.split(".");
|
||||
|
||||
// 🔍 디버깅: 첫 번째 아이템에서 키 목록 출력
|
||||
if (item && typeof item === "object") {
|
||||
const keys = Object.keys(item);
|
||||
const matchingKeys = keys.filter((k) => k.includes(fieldName));
|
||||
console.log(`🔍 getEntityJoinValue: columnName=${columnName}, fieldName=${fieldName}`);
|
||||
console.log(" 전체 키 목록:", keys);
|
||||
console.log(" 매칭 가능한 키들:", matchingKeys);
|
||||
// 🔍 엔티티 조인 컬럼 값 추출
|
||||
// 예: item_info.item_name, item_info.standard, item_info.unit
|
||||
|
||||
// 1️⃣ 소스 컬럼 추론 (item_info → item_code, warehouse_info → warehouse_id 등)
|
||||
const inferredSourceColumn = tableName.replace("_info", "_code").replace("_mng", "_id");
|
||||
|
||||
// 2️⃣ 정확한 키 매핑 시도: 소스컬럼_필드명
|
||||
// 예: item_code_item_name, item_code_standard, item_code_unit
|
||||
const exactKey = `${inferredSourceColumn}_${fieldName}`;
|
||||
if (item[exactKey] !== undefined) {
|
||||
return item[exactKey];
|
||||
}
|
||||
|
||||
// entityColumnMap에서 매핑 찾기 (예: item_info → item_code)
|
||||
// 3️⃣ 별칭 패턴: 소스컬럼_name (기본 표시 컬럼용)
|
||||
// 예: item_code_name (item_name의 별칭)
|
||||
if (fieldName === "item_name" || fieldName === "name") {
|
||||
const aliasKey = `${inferredSourceColumn}_name`;
|
||||
if (item[aliasKey] !== undefined) {
|
||||
return item[aliasKey];
|
||||
}
|
||||
}
|
||||
|
||||
// 4️⃣ entityColumnMap에서 매핑 찾기 (화면 설정에서 지정된 경우)
|
||||
if (entityColumnMap && entityColumnMap[tableName]) {
|
||||
const sourceColumn = entityColumnMap[tableName];
|
||||
const joinedColumnName = `${sourceColumn}_${fieldName}`;
|
||||
@@ -104,25 +117,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
}
|
||||
}
|
||||
|
||||
// 모든 키에서 _fieldName으로 끝나는 것 찾기
|
||||
for (const key of Object.keys(item)) {
|
||||
if (key.endsWith(`_${fieldName}`)) {
|
||||
console.log(` ✅ 매칭됨: ${key} → ${item[key]}`);
|
||||
return item[key];
|
||||
}
|
||||
}
|
||||
|
||||
// 🆕 엔티티 조인 기본 패턴: 테이블명.컬럼명 → 소스컬럼_name
|
||||
// 예: item_info.item_name → item_code_name
|
||||
// tableName에서 소스 컬럼 추론 (item_info → item_code, customer_mng → customer_id 등)
|
||||
const inferredSourceColumn = tableName.replace("_info", "_code").replace("_mng", "_id");
|
||||
const defaultAliasKey = `${inferredSourceColumn}_name`;
|
||||
if (item[defaultAliasKey] !== undefined) {
|
||||
console.log(` ✅ 기본 별칭 매칭: ${defaultAliasKey} → ${item[defaultAliasKey]}`);
|
||||
return item[defaultAliasKey];
|
||||
}
|
||||
|
||||
// 테이블명_컬럼명 형식으로 시도
|
||||
// 5️⃣ 테이블명_컬럼명 형식으로 시도
|
||||
const underscoreKey = `${tableName}_${fieldName}`;
|
||||
if (item[underscoreKey] !== undefined) {
|
||||
return item[underscoreKey];
|
||||
@@ -140,6 +135,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
const [leftGrouping, setLeftGrouping] = useState<string[]>([]);
|
||||
const [leftColumnVisibility, setLeftColumnVisibility] = useState<ColumnVisibility[]>([]);
|
||||
const [leftColumnOrder, setLeftColumnOrder] = useState<string[]>([]); // 🔧 컬럼 순서
|
||||
const [leftGroupSumConfig, setLeftGroupSumConfig] = useState<GroupSumConfig | null>(null); // 🆕 그룹별 합산 설정
|
||||
const [rightFilters, setRightFilters] = useState<TableFilter[]>([]);
|
||||
const [rightGrouping, setRightGrouping] = useState<string[]>([]);
|
||||
const [rightColumnVisibility, setRightColumnVisibility] = useState<ColumnVisibility[]>([]);
|
||||
@@ -186,6 +182,88 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
const [leftWidth, setLeftWidth] = useState(splitRatio);
|
||||
const containerRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
// 🆕 그룹별 합산된 데이터 계산
|
||||
const summedLeftData = useMemo(() => {
|
||||
console.log("🔍 [그룹합산] leftGroupSumConfig:", leftGroupSumConfig);
|
||||
|
||||
// 그룹핑이 비활성화되었거나 그룹 기준 컬럼이 없으면 원본 데이터 반환
|
||||
if (!leftGroupSumConfig?.enabled || !leftGroupSumConfig?.groupByColumn) {
|
||||
console.log("🔍 [그룹합산] 그룹핑 비활성화 - 원본 데이터 반환");
|
||||
return leftData;
|
||||
}
|
||||
|
||||
const groupByColumn = leftGroupSumConfig.groupByColumn;
|
||||
const groupMap = new Map<string, any>();
|
||||
|
||||
// 조인 컬럼인지 확인하고 실제 키 추론
|
||||
const getActualKey = (columnName: string, item: any): string => {
|
||||
if (columnName.includes(".")) {
|
||||
const [refTable, fieldName] = columnName.split(".");
|
||||
const inferredSourceColumn = refTable.replace("_info", "_code").replace("_mng", "_id");
|
||||
const exactKey = `${inferredSourceColumn}_${fieldName}`;
|
||||
console.log("🔍 [그룹합산] 조인 컬럼 키 변환:", { columnName, exactKey, hasKey: item[exactKey] !== undefined });
|
||||
if (item[exactKey] !== undefined) return exactKey;
|
||||
if (fieldName === "item_name" || fieldName === "name") {
|
||||
const aliasKey = `${inferredSourceColumn}_name`;
|
||||
if (item[aliasKey] !== undefined) return aliasKey;
|
||||
}
|
||||
}
|
||||
return columnName;
|
||||
};
|
||||
|
||||
// 숫자 타입인지 확인하는 함수
|
||||
const isNumericValue = (value: any): boolean => {
|
||||
if (value === null || value === undefined || value === "") return false;
|
||||
const num = parseFloat(String(value));
|
||||
return !isNaN(num) && isFinite(num);
|
||||
};
|
||||
|
||||
// 그룹핑 수행
|
||||
leftData.forEach((item) => {
|
||||
const actualKey = getActualKey(groupByColumn, item);
|
||||
const groupValue = String(item[actualKey] || item[groupByColumn] || "");
|
||||
|
||||
// 원본 ID 추출 (id, ID, 또는 첫 번째 값)
|
||||
const originalId = item.id || item.ID || Object.values(item)[0];
|
||||
|
||||
if (!groupMap.has(groupValue)) {
|
||||
// 첫 번째 항목을 기준으로 초기화 + 원본 ID 배열 + 원본 데이터 배열
|
||||
groupMap.set(groupValue, {
|
||||
...item,
|
||||
_groupCount: 1,
|
||||
_originalIds: [originalId],
|
||||
_originalItems: [item], // 🆕 원본 데이터 전체 저장
|
||||
});
|
||||
} else {
|
||||
const existing = groupMap.get(groupValue);
|
||||
existing._groupCount += 1;
|
||||
existing._originalIds.push(originalId);
|
||||
existing._originalItems.push(item); // 🆕 원본 데이터 추가
|
||||
|
||||
// 모든 키에 대해 숫자면 합산
|
||||
Object.keys(item).forEach((key) => {
|
||||
const value = item[key];
|
||||
if (isNumericValue(value) && key !== groupByColumn && !key.endsWith("_id") && !key.includes("code")) {
|
||||
const numValue = parseFloat(String(value));
|
||||
const existingValue = parseFloat(String(existing[key] || 0));
|
||||
existing[key] = existingValue + numValue;
|
||||
}
|
||||
});
|
||||
|
||||
groupMap.set(groupValue, existing);
|
||||
}
|
||||
});
|
||||
|
||||
const result = Array.from(groupMap.values());
|
||||
console.log("🔗 [분할패널] 그룹별 합산 결과:", {
|
||||
원본개수: leftData.length,
|
||||
그룹개수: result.length,
|
||||
그룹기준: groupByColumn,
|
||||
});
|
||||
|
||||
return result;
|
||||
}, [leftData, leftGroupSumConfig]);
|
||||
|
||||
// 컴포넌트 스타일
|
||||
// height 처리: 이미 px 단위면 그대로, 숫자면 px 추가
|
||||
const getHeightValue = () => {
|
||||
@@ -494,14 +572,77 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
// 🎯 필터 조건을 API에 전달 (entityJoinApi 사용)
|
||||
const filters = Object.keys(searchValues).length > 0 ? searchValues : undefined;
|
||||
|
||||
// 🆕 "테이블명.컬럼명" 형식의 조인 컬럼들을 additionalJoinColumns로 변환
|
||||
const configuredColumns = componentConfig.leftPanel?.columns || [];
|
||||
const additionalJoinColumns: Array<{
|
||||
sourceTable: string;
|
||||
sourceColumn: string;
|
||||
referenceTable: string;
|
||||
joinAlias: string;
|
||||
}> = [];
|
||||
|
||||
// 소스 컬럼 매핑 (item_info → item_code, warehouse_info → warehouse_id 등)
|
||||
const sourceColumnMap: Record<string, string> = {};
|
||||
|
||||
configuredColumns.forEach((col: any) => {
|
||||
const colName = typeof col === "string" ? col : col.name || col.columnName;
|
||||
if (colName && colName.includes(".")) {
|
||||
const [refTable, refColumn] = colName.split(".");
|
||||
// 소스 컬럼 추론 (item_info → item_code)
|
||||
const inferredSourceColumn = refTable.replace("_info", "_code").replace("_mng", "_id");
|
||||
|
||||
// 이미 추가된 조인인지 확인 (동일 테이블, 동일 소스컬럼)
|
||||
const existingJoin = additionalJoinColumns.find(
|
||||
(j) => j.referenceTable === refTable && j.sourceColumn === inferredSourceColumn,
|
||||
);
|
||||
|
||||
if (!existingJoin) {
|
||||
// 새로운 조인 추가 (첫 번째 컬럼)
|
||||
additionalJoinColumns.push({
|
||||
sourceTable: leftTableName,
|
||||
sourceColumn: inferredSourceColumn,
|
||||
referenceTable: refTable,
|
||||
joinAlias: `${inferredSourceColumn}_${refColumn}`,
|
||||
});
|
||||
sourceColumnMap[refTable] = inferredSourceColumn;
|
||||
}
|
||||
|
||||
// 추가 컬럼도 별도로 요청 (item_code_standard, item_code_unit 등)
|
||||
// 단, 첫 번째 컬럼과 다른 경우만
|
||||
const existingAliases = additionalJoinColumns
|
||||
.filter((j) => j.referenceTable === refTable)
|
||||
.map((j) => j.joinAlias);
|
||||
const newAlias = `${sourceColumnMap[refTable] || inferredSourceColumn}_${refColumn}`;
|
||||
|
||||
if (!existingAliases.includes(newAlias)) {
|
||||
additionalJoinColumns.push({
|
||||
sourceTable: leftTableName,
|
||||
sourceColumn: sourceColumnMap[refTable] || inferredSourceColumn,
|
||||
referenceTable: refTable,
|
||||
joinAlias: newAlias,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log("🔗 [분할패널] additionalJoinColumns:", additionalJoinColumns);
|
||||
console.log("🔗 [분할패널] configuredColumns:", configuredColumns);
|
||||
|
||||
const result = await entityJoinApi.getTableDataWithJoins(leftTableName, {
|
||||
page: 1,
|
||||
size: 100,
|
||||
search: filters, // 필터 조건 전달
|
||||
enableEntityJoin: true, // 엔티티 조인 활성화
|
||||
dataFilter: componentConfig.leftPanel?.dataFilter, // 🆕 데이터 필터 전달
|
||||
additionalJoinColumns: additionalJoinColumns.length > 0 ? additionalJoinColumns : undefined, // 🆕 추가 조인 컬럼
|
||||
});
|
||||
|
||||
// 🔍 디버깅: API 응답 데이터의 키 확인
|
||||
if (result.data && result.data.length > 0) {
|
||||
console.log("🔗 [분할패널] API 응답 첫 번째 데이터 키:", Object.keys(result.data[0]));
|
||||
console.log("🔗 [분할패널] API 응답 첫 번째 데이터:", result.data[0]);
|
||||
}
|
||||
|
||||
// 가나다순 정렬 (좌측 패널의 표시 컬럼 기준)
|
||||
const leftColumn = componentConfig.rightPanel?.relation?.leftColumn;
|
||||
if (leftColumn && result.data.length > 0) {
|
||||
@@ -527,6 +668,8 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
}
|
||||
}, [
|
||||
componentConfig.leftPanel?.tableName,
|
||||
componentConfig.leftPanel?.columns,
|
||||
componentConfig.leftPanel?.dataFilter,
|
||||
componentConfig.rightPanel?.relation?.leftColumn,
|
||||
isDesignMode,
|
||||
toast,
|
||||
@@ -563,6 +706,68 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
const keys = componentConfig.rightPanel?.relation?.keys;
|
||||
const leftTable = componentConfig.leftPanel?.tableName;
|
||||
|
||||
// 🆕 그룹 합산된 항목인 경우: 원본 데이터들로 우측 패널 표시
|
||||
if (leftItem._originalItems && leftItem._originalItems.length > 0) {
|
||||
console.log("🔗 [분할패널] 그룹 합산 항목 - 원본 개수:", leftItem._originalItems.length);
|
||||
|
||||
// 정렬 기준 컬럼 (복합키의 leftColumn들)
|
||||
const sortColumns = keys?.map((k: any) => k.leftColumn).filter(Boolean) || [];
|
||||
console.log("🔗 [분할패널] 정렬 기준 컬럼:", sortColumns);
|
||||
|
||||
// 정렬 함수
|
||||
const sortByKeys = (data: any[]) => {
|
||||
if (sortColumns.length === 0) return data;
|
||||
return [...data].sort((a, b) => {
|
||||
for (const col of sortColumns) {
|
||||
const aVal = String(a[col] || "");
|
||||
const bVal = String(b[col] || "");
|
||||
const cmp = aVal.localeCompare(bVal, "ko-KR");
|
||||
if (cmp !== 0) return cmp;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
};
|
||||
|
||||
// 원본 데이터를 그대로 우측 패널에 표시 (이력 테이블과 동일 테이블인 경우)
|
||||
if (leftTable === rightTableName) {
|
||||
const sortedData = sortByKeys(leftItem._originalItems);
|
||||
console.log("🔗 [분할패널] 동일 테이블 - 정렬된 원본 데이터:", sortedData.length);
|
||||
setRightData(sortedData);
|
||||
return;
|
||||
}
|
||||
|
||||
// 다른 테이블인 경우: 원본 ID들로 조회
|
||||
const { entityJoinApi } = await import("@/lib/api/entityJoin");
|
||||
const allResults: any[] = [];
|
||||
|
||||
// 각 원본 항목에 대해 조회
|
||||
for (const originalItem of leftItem._originalItems) {
|
||||
const searchConditions: Record<string, any> = {};
|
||||
keys?.forEach((key: any) => {
|
||||
if (key.leftColumn && key.rightColumn && originalItem[key.leftColumn] !== undefined) {
|
||||
searchConditions[key.rightColumn] = originalItem[key.leftColumn];
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(searchConditions).length > 0) {
|
||||
const result = await entityJoinApi.getTableDataWithJoins(rightTableName, {
|
||||
search: searchConditions,
|
||||
enableEntityJoin: true,
|
||||
size: 1000,
|
||||
});
|
||||
if (result.data) {
|
||||
allResults.push(...result.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 정렬 적용
|
||||
const sortedResults = sortByKeys(allResults);
|
||||
console.log("🔗 [분할패널] 그룹 합산 - 우측 패널 정렬된 데이터:", sortedResults.length);
|
||||
setRightData(sortedResults);
|
||||
return;
|
||||
}
|
||||
|
||||
// 🆕 복합키 지원
|
||||
if (keys && keys.length > 0 && leftTable) {
|
||||
// 복합키: 여러 조건으로 필터링
|
||||
@@ -703,7 +908,28 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
const uniqueValues = new Set<string>();
|
||||
|
||||
leftData.forEach((item) => {
|
||||
const value = item[columnName];
|
||||
// 🆕 조인 컬럼 처리 (item_info.standard → item_code_standard)
|
||||
let value: any;
|
||||
|
||||
if (columnName.includes(".")) {
|
||||
// 조인 컬럼: getEntityJoinValue와 동일한 로직 적용
|
||||
const [refTable, fieldName] = columnName.split(".");
|
||||
const inferredSourceColumn = refTable.replace("_info", "_code").replace("_mng", "_id");
|
||||
|
||||
// 정확한 키로 먼저 시도
|
||||
const exactKey = `${inferredSourceColumn}_${fieldName}`;
|
||||
value = item[exactKey];
|
||||
|
||||
// 기본 별칭 패턴 시도 (item_code_name)
|
||||
if (value === undefined && (fieldName === "item_name" || fieldName === "name")) {
|
||||
const aliasKey = `${inferredSourceColumn}_name`;
|
||||
value = item[aliasKey];
|
||||
}
|
||||
} else {
|
||||
// 일반 컬럼
|
||||
value = item[columnName];
|
||||
}
|
||||
|
||||
if (value !== null && value !== undefined && value !== "") {
|
||||
// _name 필드 우선 사용 (category/entity type)
|
||||
const displayValue = item[`${columnName}_name`] || value;
|
||||
@@ -727,6 +953,15 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
const leftTableId = `split-panel-left-${component.id}`;
|
||||
// 🔧 화면에 표시되는 컬럼 사용 (columns 속성)
|
||||
const configuredColumns = componentConfig.leftPanel?.columns || [];
|
||||
|
||||
// 🆕 설정에서 지정한 라벨 맵 생성
|
||||
const configuredLabels: Record<string, string> = {};
|
||||
configuredColumns.forEach((col: any) => {
|
||||
if (typeof col === "object" && col.name && col.label) {
|
||||
configuredLabels[col.name] = col.label;
|
||||
}
|
||||
});
|
||||
|
||||
const displayColumns = configuredColumns
|
||||
.map((col: any) => {
|
||||
if (typeof col === "string") return col;
|
||||
@@ -744,7 +979,8 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
tableName: leftTableName,
|
||||
columns: displayColumns.map((col: string) => ({
|
||||
columnName: col,
|
||||
columnLabel: leftColumnLabels[col] || col,
|
||||
// 🆕 우선순위: 1) 설정에서 지정한 라벨 2) DB 라벨 3) 컬럼명
|
||||
columnLabel: configuredLabels[col] || leftColumnLabels[col] || col,
|
||||
inputType: "text",
|
||||
visible: true,
|
||||
width: 150,
|
||||
@@ -756,6 +992,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
onColumnVisibilityChange: setLeftColumnVisibility,
|
||||
onColumnOrderChange: setLeftColumnOrder, // 🔧 컬럼 순서 변경 콜백 추가
|
||||
getColumnUniqueValues: getLeftColumnUniqueValues, // 🔧 고유값 가져오기 함수 추가
|
||||
onGroupSumChange: setLeftGroupSumConfig, // 🆕 그룹별 합산 설정 콜백
|
||||
});
|
||||
|
||||
return () => unregisterTable(leftTableId);
|
||||
@@ -1712,16 +1949,25 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
</div>
|
||||
) : (
|
||||
(() => {
|
||||
// 🆕 그룹별 합산된 데이터 사용
|
||||
const dataSource = summedLeftData;
|
||||
console.log(
|
||||
"🔍 [테이블모드 렌더링] dataSource 개수:",
|
||||
dataSource.length,
|
||||
"leftGroupSumConfig:",
|
||||
leftGroupSumConfig,
|
||||
);
|
||||
|
||||
// 🔧 로컬 검색 필터 적용
|
||||
const filteredData = leftSearchQuery
|
||||
? leftData.filter((item) => {
|
||||
? dataSource.filter((item) => {
|
||||
const searchLower = leftSearchQuery.toLowerCase();
|
||||
return Object.entries(item).some(([key, value]) => {
|
||||
if (value === null || value === undefined) return false;
|
||||
return String(value).toLowerCase().includes(searchLower);
|
||||
});
|
||||
})
|
||||
: leftData;
|
||||
: dataSource;
|
||||
|
||||
// 🔧 가시성 처리된 컬럼 사용
|
||||
const columnsToShow =
|
||||
@@ -1917,16 +2163,25 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
</div>
|
||||
) : (
|
||||
(() => {
|
||||
// 🆕 그룹별 합산된 데이터 사용
|
||||
const dataToDisplay = summedLeftData;
|
||||
console.log(
|
||||
"🔍 [렌더링] dataToDisplay 개수:",
|
||||
dataToDisplay.length,
|
||||
"leftGroupSumConfig:",
|
||||
leftGroupSumConfig,
|
||||
);
|
||||
|
||||
// 검색 필터링 (클라이언트 사이드)
|
||||
const filteredLeftData = leftSearchQuery
|
||||
? leftData.filter((item) => {
|
||||
? dataToDisplay.filter((item) => {
|
||||
const searchLower = leftSearchQuery.toLowerCase();
|
||||
return Object.entries(item).some(([key, value]) => {
|
||||
if (value === null || value === undefined) return false;
|
||||
return String(value).toLowerCase().includes(searchLower);
|
||||
});
|
||||
})
|
||||
: leftData;
|
||||
: dataToDisplay;
|
||||
|
||||
// 재귀 렌더링 함수
|
||||
const renderTreeItem = (item: any, index: number): React.ReactNode => {
|
||||
@@ -2174,23 +2429,53 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
if (isTableMode) {
|
||||
// 테이블 모드 렌더링
|
||||
const displayColumns = componentConfig.rightPanel?.columns || [];
|
||||
const columnsToShow =
|
||||
displayColumns.length > 0
|
||||
? displayColumns.map((col) => ({
|
||||
...col,
|
||||
label: rightColumnLabels[col.name] || col.label || col.name,
|
||||
format: col.format, // 🆕 포맷 설정 유지
|
||||
}))
|
||||
: Object.keys(filteredData[0] || {})
|
||||
.filter((key) => shouldShowField(key))
|
||||
.slice(0, 5)
|
||||
.map((key) => ({
|
||||
name: key,
|
||||
label: rightColumnLabels[key] || key,
|
||||
width: 150,
|
||||
align: "left" as const,
|
||||
format: undefined, // 🆕 기본값
|
||||
}));
|
||||
|
||||
// 🆕 그룹 합산 모드일 때: 복합키 컬럼을 우선 표시
|
||||
const relationKeys = componentConfig.rightPanel?.relation?.keys || [];
|
||||
const keyColumns = relationKeys.map((k: any) => k.leftColumn).filter(Boolean);
|
||||
const isGroupedMode = selectedLeftItem?._originalItems?.length > 0;
|
||||
|
||||
let columnsToShow: any[] = [];
|
||||
|
||||
if (displayColumns.length > 0) {
|
||||
// 설정된 컬럼 사용
|
||||
columnsToShow = displayColumns.map((col) => ({
|
||||
...col,
|
||||
label: rightColumnLabels[col.name] || col.label || col.name,
|
||||
format: col.format,
|
||||
}));
|
||||
|
||||
// 🆕 그룹 합산 모드이고, 키 컬럼이 표시 목록에 없으면 맨 앞에 추가
|
||||
if (isGroupedMode && keyColumns.length > 0) {
|
||||
const existingColNames = columnsToShow.map((c) => c.name);
|
||||
const missingKeyColumns = keyColumns.filter((k: string) => !existingColNames.includes(k));
|
||||
|
||||
if (missingKeyColumns.length > 0) {
|
||||
const keyColsToAdd = missingKeyColumns.map((colName: string) => ({
|
||||
name: colName,
|
||||
label: rightColumnLabels[colName] || colName,
|
||||
width: 120,
|
||||
align: "left" as const,
|
||||
format: undefined,
|
||||
_isKeyColumn: true, // 구분용 플래그
|
||||
}));
|
||||
columnsToShow = [...keyColsToAdd, ...columnsToShow];
|
||||
console.log("🔗 [우측패널] 그룹모드 - 키 컬럼 추가:", missingKeyColumns);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 기본 컬럼 자동 생성
|
||||
columnsToShow = Object.keys(filteredData[0] || {})
|
||||
.filter((key) => shouldShowField(key))
|
||||
.slice(0, 5)
|
||||
.map((key) => ({
|
||||
name: key,
|
||||
label: rightColumnLabels[key] || key,
|
||||
width: 150,
|
||||
align: "left" as const,
|
||||
format: undefined,
|
||||
}));
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
|
||||
Reference in New Issue
Block a user