diff options
Diffstat (limited to 'components/form-data/form-data-table-columns.tsx')
| -rw-r--r-- | components/form-data/form-data-table-columns.tsx | 95 |
1 files changed, 56 insertions, 39 deletions
diff --git a/components/form-data/form-data-table-columns.tsx b/components/form-data/form-data-table-columns.tsx index 930e113b..2a065d1b 100644 --- a/components/form-data/form-data-table-columns.tsx +++ b/components/form-data/form-data-table-columns.tsx @@ -103,53 +103,59 @@ function getHeaderText(col: DataTableColumnJSON): string { } /** - * 컬럼들을 head 값에 따라 그룹핑하는 헬퍼 함수 + * 컬럼들을 seq 순서대로 배치하면서 연속된 같은 head를 가진 컬럼들을 그룹으로 묶는 함수 */ function groupColumnsByHead(columns: DataTableColumnJSON[]): ColumnDef<any>[] { - const groupedColumns: ColumnDef<any>[] = []; - const groupMap = new Map<string, DataTableColumnJSON[]>(); - const ungroupedColumns: DataTableColumnJSON[] = []; + const result: ColumnDef<any>[] = []; + let i = 0; - // head 값에 따라 컬럼들을 그룹핑 - columns.forEach(col => { - if (col.head && col.head.trim()) { - const groupKey = col.head.trim(); - if (!groupMap.has(groupKey)) { - groupMap.set(groupKey, []); - } - groupMap.get(groupKey)!.push(col); - } else { - ungroupedColumns.push(col); + while (i < columns.length) { + const currentCol = columns[i]; + + // head가 없거나 빈 문자열인 경우 일반 컬럼으로 처리 + if (!currentCol.head || !currentCol.head.trim()) { + result.push(createColumnDef(currentCol, false)); + i++; + continue; + } + + // 같은 head를 가진 연속된 컬럼들을 찾기 + const groupHead = currentCol.head.trim(); + const groupColumns: DataTableColumnJSON[] = [currentCol]; + let j = i + 1; + + while (j < columns.length && columns[j].head && columns[j].head.trim() === groupHead) { + groupColumns.push(columns[j]); + j++; } - }); - // 그룹핑된 컬럼들 처리 - groupMap.forEach((groupColumns, groupHeader) => { + // 그룹에 컬럼이 하나만 있으면 일반 컬럼으로 처리 if (groupColumns.length === 1) { - // 그룹에 컬럼이 하나만 있으면 일반 컬럼으로 처리 - ungroupedColumns.push(groupColumns[0]); + result.push(createColumnDef(currentCol, false)); } else { - // 그룹 컬럼 생성 + // 그룹 컬럼 생성 (구분선 스타일 적용) const groupColumn: ColumnDef<any> = { - header: groupHeader, - columns: groupColumns.map(col => createColumnDef(col)) + id: `group-${groupHead.replace(/\s+/g, '-')}`, + header: groupHead, + columns: groupColumns.map(col => createColumnDef(col, true)), + meta: { + isGroupColumn: true, + groupBorders: true, // 그룹 구분선 표시 플래그 + } }; - groupedColumns.push(groupColumn); + result.push(groupColumn); } - }); - // 그룹핑되지 않은 컬럼들 처리 - ungroupedColumns.forEach(col => { - groupedColumns.push(createColumnDef(col)); - }); + i = j; // 다음 그룹으로 이동 + } - return groupedColumns; + return result; } /** * 개별 컬럼 정의를 생성하는 헬퍼 함수 */ -function createColumnDef(col: DataTableColumnJSON): ColumnDef<any> { +function createColumnDef(col: DataTableColumnJSON, isInGroup: boolean = false): ColumnDef<any> { return { accessorKey: col.key, header: ({ column }) => ( @@ -165,6 +171,8 @@ function createColumnDef(col: DataTableColumnJSON): ColumnDef<any> { paddingFactor: 1.2, maxWidth: col.key === "TAG_NO" ? 120 : 150, isReadOnly: col.shi === true, + isInGroup, // 그룹 내 컬럼인지 표시 + groupBorders: isInGroup, // 그룹 구분선 표시 플래그 }, cell: ({ row }) => { @@ -173,10 +181,19 @@ function createColumnDef(col: DataTableColumnJSON): ColumnDef<any> { // SHI 필드만 읽기 전용으로 처리 const isReadOnly = col.shi === true; + // 그룹 구분선 스타일 클래스 추가 + const groupBorderClass = isInGroup ? "group-column-border" : ""; const readOnlyClass = isReadOnly ? "read-only-cell" : ""; - const cellStyle = isReadOnly - ? { backgroundColor: '#f5f5f5', color: '#666', cursor: 'not-allowed' } - : {}; + const combinedClass = [groupBorderClass, readOnlyClass].filter(Boolean).join(" "); + + const cellStyle = { + ...(isReadOnly && { backgroundColor: '#f5f5f5', color: '#666', cursor: 'not-allowed' }), + ...(isInGroup && { + borderLeft: '2px solid #e2e8f0', + borderRight: '2px solid #e2e8f0', + position: 'relative' as const + }) + }; // 툴팁 메시지 설정 (SHI 필드만) const tooltipMessage = isReadOnly ? "SHI 전용 필드입니다" : ""; @@ -188,7 +205,7 @@ function createColumnDef(col: DataTableColumnJSON): ColumnDef<any> { return ( <div - className={readOnlyClass} + className={combinedClass} style={cellStyle} title={tooltipMessage} > @@ -204,7 +221,7 @@ function createColumnDef(col: DataTableColumnJSON): ColumnDef<any> { case "NUMBER": return ( <div - className={readOnlyClass} + className={combinedClass} style={cellStyle} title={tooltipMessage} > @@ -215,7 +232,7 @@ function createColumnDef(col: DataTableColumnJSON): ColumnDef<any> { case "LIST": return ( <div - className={readOnlyClass} + className={combinedClass} style={cellStyle} title={tooltipMessage} > @@ -227,7 +244,7 @@ function createColumnDef(col: DataTableColumnJSON): ColumnDef<any> { default: return ( <div - className={readOnlyClass} + className={combinedClass} style={cellStyle} title={tooltipMessage} > @@ -243,7 +260,7 @@ function createColumnDef(col: DataTableColumnJSON): ColumnDef<any> { * getColumns 함수 * 1) columnsJSON 배열을 필터링 (hidden이 true가 아닌 것들만) * 2) seq에 따라 정렬 - * 3) head 값에 따라 컬럼 그룹핑 + * 3) seq 순서를 유지하면서 연속된 같은 head를 가진 컬럼들을 그룹으로 묶기 * 4) 체크박스 컬럼 추가 * 5) 마지막에 "Action" 칼럼 추가 */ @@ -318,7 +335,7 @@ export function getColumns<TData extends object>({ }; columns.push(selectColumn); - // (2) 기본 컬럼들 (head에 따라 그룹핑 처리) + // (2) 기본 컬럼들 (seq 순서를 유지하면서 head에 따라 그룹핑 처리) const groupedColumns = groupColumnsByHead(visibleColumns); columns.push(...groupedColumns); |
