검색필터 수정사항

This commit is contained in:
kjs 2025-09-23 15:31:27 +09:00
parent c557fc5d56
commit f15c1fa114
4 changed files with 268 additions and 345 deletions

View File

@ -25,7 +25,7 @@ export const ResponsiveDesignerContainer: React.FC<ResponsiveDesignerContainerPr
onScaleChange, onScaleChange,
}) => { }) => {
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const [viewMode, setViewMode] = useState<DesignerViewMode>("fit"); const [viewMode, setViewMode] = useState<DesignerViewMode>("original");
const [customScale, setCustomScale] = useState(1); const [customScale, setCustomScale] = useState(1);
const containerSize = useContainerSize(containerRef); const containerSize = useContainerSize(containerRef);

View File

@ -317,7 +317,7 @@ export const AdvancedSearchFilters: React.FC<AdvancedSearchFiltersProps> = ({
}).length; }).length;
return ( return (
<div className={cn("space-y-4", className)}> <div className={cn("space-y-2", className)}>
{/* 필터 헤더 */} {/* 필터 헤더 */}
<div className="text-muted-foreground flex items-center gap-2 text-sm"> <div className="text-muted-foreground flex items-center gap-2 text-sm">
<Search className="h-3 w-3" /> <Search className="h-3 w-3" />
@ -339,7 +339,7 @@ export const AdvancedSearchFilters: React.FC<AdvancedSearchFiltersProps> = ({
}; };
return ( return (
<div key={filter.columnName} className={`space-y-1 ${getFilterWidth()}`}> <div key={filter.columnName} className={`space-y-0.5 ${getFilterWidth()}`}>
<label className="text-muted-foreground text-xs font-medium">{filter.label}</label> <label className="text-muted-foreground text-xs font-medium">{filter.label}</label>
{renderFilter(filter)} {renderFilter(filter)}
</div> </div>

View File

@ -0,0 +1,188 @@
"use client";
import React from "react";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Checkbox } from "@/components/ui/checkbox";
import { ArrowUp, ArrowDown, ArrowUpDown } from "lucide-react";
import { cn } from "@/lib/utils";
import { ColumnConfig } from "./types";
interface SingleTableWithStickyProps {
visibleColumns: ColumnConfig[];
data: Record<string, any>[];
columnLabels: Record<string, string>;
sortColumn: string | null;
sortDirection: "asc" | "desc";
tableConfig: any;
isDesignMode: boolean;
isAllSelected: boolean;
handleSort: (columnName: string) => void;
handleSelectAll: (checked: boolean) => void;
handleRowClick: (row: any) => void;
renderCheckboxCell: (row: any, index: number) => React.ReactNode;
formatCellValue: (value: any, format?: string, columnName?: string) => string;
getColumnWidth: (column: ColumnConfig) => number;
}
export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
visibleColumns,
data,
columnLabels,
sortColumn,
sortDirection,
tableConfig,
isDesignMode,
isAllSelected,
handleSort,
handleSelectAll,
handleRowClick,
renderCheckboxCell,
formatCellValue,
getColumnWidth,
}) => {
const checkboxConfig = tableConfig.checkbox || {};
return (
<div className="relative h-full w-full overflow-auto">
<Table className="w-full">
<TableHeader className={tableConfig.stickyHeader ? "sticky top-0 z-20 bg-white" : ""}>
<TableRow>
{visibleColumns.map((column, colIndex) => {
// 왼쪽 고정 컬럼들의 누적 너비 계산
const leftFixedWidth = visibleColumns
.slice(0, colIndex)
.filter((col) => col.fixed === "left")
.reduce((sum, col) => sum + getColumnWidth(col), 0);
// 오른쪽 고정 컬럼들의 누적 너비 계산
const rightFixedColumns = visibleColumns.filter((col) => col.fixed === "right");
const rightFixedIndex = rightFixedColumns.findIndex((col) => col.columnName === column.columnName);
const rightFixedWidth =
rightFixedIndex >= 0
? rightFixedColumns.slice(rightFixedIndex + 1).reduce((sum, col) => sum + getColumnWidth(col), 0)
: 0;
return (
<TableHead
key={column.columnName}
className={cn(
column.columnName === "__checkbox__"
? "h-10 border-b px-4 py-2 text-center align-middle"
: "h-10 cursor-pointer border-b px-4 py-2 text-left align-middle font-medium whitespace-nowrap text-gray-900 select-none",
`text-${column.align}`,
column.sortable && "hover:bg-gray-50",
// 고정 컬럼 스타일
column.fixed === "left" && "sticky z-10 border-r bg-white shadow-sm",
column.fixed === "right" && "sticky z-10 border-l bg-white shadow-sm",
// 숨김 컬럼 스타일 (디자인 모드에서만)
isDesignMode && column.hidden && "bg-gray-100/50 opacity-40",
)}
style={{
width: getColumnWidth(column),
minWidth: getColumnWidth(column),
maxWidth: getColumnWidth(column),
// sticky 위치 설정
...(column.fixed === "left" && { left: leftFixedWidth }),
...(column.fixed === "right" && { right: rightFixedWidth }),
}}
onClick={() => column.sortable && handleSort(column.columnName)}
>
<div className="flex items-center gap-2">
{column.columnName === "__checkbox__" ? (
checkboxConfig.selectAll && (
<Checkbox checked={isAllSelected} onCheckedChange={handleSelectAll} aria-label="전체 선택" />
)
) : (
<>
<span className="flex-1 truncate">
{columnLabels[column.columnName] || column.displayName || column.columnName}
</span>
{column.sortable && (
<span className="ml-1">
{sortColumn === column.columnName ? (
sortDirection === "asc" ? (
<ArrowUp className="h-3 w-3 text-blue-600" />
) : (
<ArrowDown className="h-3 w-3 text-blue-600" />
)
) : (
<ArrowUpDown className="h-3 w-3 text-gray-400" />
)}
</span>
)}
</>
)}
</div>
</TableHead>
);
})}
</TableRow>
</TableHeader>
<TableBody>
{data.length === 0 ? (
<TableRow>
<TableCell colSpan={visibleColumns.length} className="py-8 text-center text-gray-500">
</TableCell>
</TableRow>
) : (
data.map((row, index) => (
<TableRow
key={`row-${index}`}
className={cn(
"h-10 cursor-pointer border-b leading-none",
tableConfig.tableStyle?.hoverEffect && "hover:bg-gray-50",
tableConfig.tableStyle?.alternateRows && index % 2 === 1 && "bg-gray-50/30",
)}
style={{ minHeight: "40px", height: "40px", lineHeight: "1" }}
onClick={() => handleRowClick(row)}
>
{visibleColumns.map((column, colIndex) => {
// 왼쪽 고정 컬럼들의 누적 너비 계산
const leftFixedWidth = visibleColumns
.slice(0, colIndex)
.filter((col) => col.fixed === "left")
.reduce((sum, col) => sum + getColumnWidth(col), 0);
// 오른쪽 고정 컬럼들의 누적 너비 계산
const rightFixedColumns = visibleColumns.filter((col) => col.fixed === "right");
const rightFixedIndex = rightFixedColumns.findIndex((col) => col.columnName === column.columnName);
const rightFixedWidth =
rightFixedIndex >= 0
? rightFixedColumns.slice(rightFixedIndex + 1).reduce((sum, col) => sum + getColumnWidth(col), 0)
: 0;
return (
<TableCell
key={`cell-${column.columnName}`}
className={cn(
"h-10 px-4 py-2 align-middle text-sm whitespace-nowrap",
`text-${column.align}`,
// 고정 컬럼 스타일
column.fixed === "left" && "sticky z-10 border-r bg-white",
column.fixed === "right" && "sticky z-10 border-l bg-white",
)}
style={{
minHeight: "40px",
height: "40px",
verticalAlign: "middle",
// sticky 위치 설정
...(column.fixed === "left" && { left: leftFixedWidth }),
...(column.fixed === "right" && { right: rightFixedWidth }),
}}
>
{column.columnName === "__checkbox__"
? renderCheckboxCell(row, index)
: formatCellValue(row[column.columnName], column.format, column.columnName) || "\u00A0"}
</TableCell>
);
})}
</TableRow>
))
)}
</TableBody>
</Table>
</div>
);
};

View File

@ -23,6 +23,7 @@ import { Checkbox } from "@/components/ui/checkbox";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { AdvancedSearchFilters } from "@/components/screen/filters/AdvancedSearchFilters"; import { AdvancedSearchFilters } from "@/components/screen/filters/AdvancedSearchFilters";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { SingleTableWithSticky } from "./SingleTableWithSticky";
export interface TableListComponentProps { export interface TableListComponentProps {
component: any; component: any;
@ -113,39 +114,67 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
maxBatchSize: 5, maxBatchSize: 5,
}); });
// 높이 계산 함수 // 높이 계산 함수 (메모이제이션)
const calculateOptimalHeight = () => { const optimalHeight = useMemo(() => {
// 50개 이상일 때는 20개 기준으로 높이 고정 // 50개 이상일 때는 20개 기준으로 높이 고정하고 스크롤 생성
const displayPageSize = localPageSize >= 50 ? 20 : localPageSize; // 50개 미만일 때는 실제 데이터 개수에 맞춰서 스크롤 없이 표시
const headerHeight = 48; // 테이블 헤더 const actualDataCount = Math.min(data.length, localPageSize);
const rowHeight = 40; // 각 행 높이 (normal) const displayPageSize = localPageSize >= 50 ? 20 : Math.max(actualDataCount, 5);
const searchHeight = tableConfig.filter?.enabled ? 48 : 0; // 검색 영역
const footerHeight = tableConfig.showFooter ? 56 : 0; // 페이지네이션
const padding = 8; // 여백
return headerHeight + displayPageSize * rowHeight + searchHeight + footerHeight + padding; const headerHeight = 50; // 테이블 헤더
}; const rowHeight = 42; // 각 행 높이
const searchHeight = tableConfig.filter?.enabled ? 80 : 0; // 검색 영역
const footerHeight = tableConfig.showFooter ? 60 : 0; // 페이지네이션
const titleHeight = tableConfig.showHeader ? 60 : 0; // 제목 영역
const padding = 40; // 여백
const calculatedHeight =
titleHeight + searchHeight + headerHeight + displayPageSize * rowHeight + footerHeight + padding;
console.log("🔍 테이블 높이 계산:", {
actualDataCount,
localPageSize,
displayPageSize,
willHaveScroll: localPageSize >= 50,
titleHeight,
searchHeight,
headerHeight,
rowHeight,
footerHeight,
padding,
calculatedHeight,
finalHeight: `${calculatedHeight}px`,
});
// 추가 디버깅: 실제 데이터 상황
console.log("🔍 실제 데이터 상황:", {
actualDataLength: data.length,
localPageSize,
currentPage,
totalItems,
totalPages,
});
return calculatedHeight;
}, [data.length, localPageSize, tableConfig.filter?.enabled, tableConfig.showFooter, tableConfig.showHeader]);
// 스타일 계산 // 스타일 계산
const componentStyle: React.CSSProperties = { const componentStyle: React.CSSProperties = {
width: "100%", width: "100%",
height: height: `${optimalHeight}px`, // 20개 데이터를 모두 보여주는 높이
tableConfig.height === "fixed" minHeight: `${optimalHeight}px`, // 최소 높이 보장
? `${tableConfig.fixedHeight || calculateOptimalHeight()}px`
: tableConfig.height === "auto"
? `${calculateOptimalHeight()}px`
: "100%",
...component.style, ...component.style,
...style, ...style,
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
boxSizing: "border-box", // 패딩/보더 포함한 크기 계산
}; };
// 디자인 모드 스타일 // 디자인 모드 스타일
if (isDesignMode) { if (isDesignMode) {
componentStyle.border = "1px dashed #cbd5e1"; componentStyle.border = "1px dashed #cbd5e1";
componentStyle.borderColor = isSelected ? "#3b82f6" : "#cbd5e1"; componentStyle.borderColor = isSelected ? "#3b82f6" : "#cbd5e1";
componentStyle.minHeight = "200px"; // minHeight 제거 - 실제 데이터에 맞는 높이 사용
} }
// 컬럼 라벨 정보 가져오기 // 컬럼 라벨 정보 가져오기
@ -637,28 +666,8 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
return columns; return columns;
}, [displayColumns, tableConfig.columns, tableConfig.checkbox]); }, [displayColumns, tableConfig.columns, tableConfig.checkbox]);
// 컬럼을 고정 위치별로 분류 // columnsByPosition은 SingleTableWithSticky에서 사용하지 않으므로 제거
const columnsByPosition = useMemo(() => { // 기존 테이블에서만 필요한 경우 다시 추가 가능
const leftFixed: ColumnConfig[] = [];
const rightFixed: ColumnConfig[] = [];
const normal: ColumnConfig[] = [];
visibleColumns.forEach((col) => {
if (col.fixed === "left") {
leftFixed.push(col);
} else if (col.fixed === "right") {
rightFixed.push(col);
} else {
normal.push(col);
}
});
// 고정 컬럼들은 fixedOrder로 정렬
leftFixed.sort((a, b) => (a.fixedOrder || 0) - (b.fixedOrder || 0));
rightFixed.sort((a, b) => (a.fixedOrder || 0) - (b.fixedOrder || 0));
return { leftFixed, rightFixed, normal };
}, [visibleColumns]);
// 가로 스크롤이 필요한지 계산 // 가로 스크롤이 필요한지 계산
const needsHorizontalScroll = useMemo(() => { const needsHorizontalScroll = useMemo(() => {
@ -893,7 +902,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
{/* 고급 검색 필터 - 항상 표시 (컬럼 정보 기반 자동 생성) */} {/* 고급 검색 필터 - 항상 표시 (컬럼 정보 기반 자동 생성) */}
{tableConfig.filter?.enabled && visibleColumns && visibleColumns.length > 0 && ( {tableConfig.filter?.enabled && visibleColumns && visibleColumns.length > 0 && (
<> <>
<Separator className="my-2" /> <Separator className="my-1" />
<AdvancedSearchFilters <AdvancedSearchFilters
filters={tableConfig.filter?.filters || []} // 설정된 필터 사용, 없으면 자동 생성 filters={tableConfig.filter?.filters || []} // 설정된 필터 사용, 없으면 자동 생성
searchValues={searchValues} searchValues={searchValues}
@ -918,7 +927,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
)} )}
{/* 테이블 컨텐츠 */} {/* 테이블 컨텐츠 */}
<div className={`flex-1 ${localPageSize >= 50 ? "overflow-auto" : "overflow-hidden"}`}> <div className={`w-full ${localPageSize >= 50 ? "flex-1 overflow-auto" : ""}`}>
{loading ? ( {loading ? (
<div className="flex h-full items-center justify-center"> <div className="flex h-full items-center justify-center">
<div className="text-center"> <div className="text-center">
@ -934,317 +943,43 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
</div> </div>
</div> </div>
) : needsHorizontalScroll ? ( ) : needsHorizontalScroll ? (
// 가로 스크롤이 필요한 경우 - 고정 컬럼 지원 테이블 // 가로 스크롤이 필요한 경우 - 단일 테이블에서 sticky 컬럼 사용
<div className="relative flex h-full"> <SingleTableWithSticky
{/* 왼쪽 고정 컬럼 */} visibleColumns={visibleColumns}
{columnsByPosition.leftFixed.length > 0 && ( data={data}
<div className="flex-shrink-0 border-r bg-gray-50/50"> columnLabels={columnLabels}
<table sortColumn={sortColumn}
className="table-fixed-layout table-auto" sortDirection={sortDirection}
style={{ borderCollapse: "collapse", margin: 0, padding: 0 }} tableConfig={tableConfig}
> isDesignMode={isDesignMode}
<thead className={tableConfig.stickyHeader ? "sticky top-0 z-20 bg-white" : ""}> isAllSelected={isAllSelected}
<tr> handleSort={handleSort}
{columnsByPosition.leftFixed.map((column) => ( handleSelectAll={handleSelectAll}
<th handleRowClick={handleRowClick}
key={`fixed-left-${column.columnName}`} renderCheckboxCell={renderCheckboxCell}
className={cn( formatCellValue={formatCellValue}
column.columnName === "__checkbox__" getColumnWidth={getColumnWidth}
? "h-12 border-b px-4 py-3 text-center align-middle" />
: "h-12 cursor-pointer border-b px-4 py-3 text-left align-middle font-medium whitespace-nowrap text-gray-900 select-none",
`text-${column.align}`,
column.sortable && "hover:bg-gray-50",
// 숨김 컬럼 스타일 (디자인 모드에서만)
isDesignMode && column.hidden && "bg-gray-100/50 opacity-40",
)}
style={{
minWidth: `${getColumnWidth(column)}px`,
minHeight: "48px",
height: "48px",
verticalAlign: "middle",
lineHeight: "1",
boxSizing: "border-box",
}}
onClick={() => column.sortable && handleSort(column.columnName)}
>
{column.columnName === "__checkbox__" ? (
renderCheckboxHeader()
) : (
<div className="flex items-center space-x-1">
<span className="text-sm">{columnLabels[column.columnName] || column.displayName}</span>
{column.sortable && (
<div className="flex flex-col">
{sortColumn === column.columnName ? (
sortDirection === "asc" ? (
<ArrowUp className="h-3 w-3" />
) : (
<ArrowDown className="h-3 w-3" />
)
) : (
<ArrowUpDown className="h-3 w-3 text-gray-400" />
)}
</div>
)}
</div>
)}
</th>
))}
</tr>
</thead>
<tbody>
{data.length === 0 ? (
<tr>
<td colSpan={columnsByPosition.leftFixed.length} className="py-8 text-center text-gray-500">
</td>
</tr>
) : (
data.map((row, index) => (
<tr
key={`fixed-left-row-${index}`}
className={cn(
"h-12 cursor-pointer border-b leading-none",
tableConfig.tableStyle?.hoverEffect && "hover:bg-gray-50",
tableConfig.tableStyle?.alternateRows && index % 2 === 1 && "bg-gray-50/50",
)}
style={{ minHeight: "48px", height: "48px", lineHeight: "1" }}
onClick={() => handleRowClick(row)}
>
{columnsByPosition.leftFixed.map((column) => (
<td
key={`fixed-left-cell-${column.columnName}`}
className={cn(
"h-12 px-4 py-3 align-middle text-sm whitespace-nowrap",
`text-${column.align}`,
)}
style={{ minHeight: "48px", height: "48px", verticalAlign: "middle" }}
>
{column.columnName === "__checkbox__"
? renderCheckboxCell(row, index)
: formatCellValue(row[column.columnName], column.format, column.columnName) || "\u00A0"}
</td>
))}
</tr>
))
)}
</tbody>
</table>
</div>
)}
{/* 스크롤 가능한 중앙 컬럼들 */}
<div className="flex-1 overflow-x-auto">
<table
className="table-fixed-layout w-full table-auto"
style={{ borderCollapse: "collapse", margin: 0, padding: 0 }}
>
<thead className={tableConfig.stickyHeader ? "sticky top-0 z-10 bg-white" : ""}>
<tr>
{columnsByPosition.normal.map((column) => (
<th
key={`normal-${column.columnName}`}
style={{
minWidth: `${getColumnWidth(column)}px`,
minHeight: "48px",
height: "48px",
verticalAlign: "middle",
lineHeight: "1",
boxSizing: "border-box",
}}
className={cn(
column.columnName === "__checkbox__"
? "h-12 border-b px-4 py-3 text-center align-middle"
: "cursor-pointer border-b px-4 py-3 text-left align-middle font-medium whitespace-nowrap text-gray-900 select-none",
`text-${column.align}`,
column.sortable && "hover:bg-gray-50",
// 숨김 컬럼 스타일 (디자인 모드에서만)
isDesignMode && column.hidden && "bg-gray-100/50 opacity-40",
)}
onClick={() => column.sortable && handleSort(column.columnName)}
>
{column.columnName === "__checkbox__" ? (
renderCheckboxHeader()
) : (
<div className="flex items-center space-x-1">
<span className="text-sm">{columnLabels[column.columnName] || column.displayName}</span>
{column.sortable && (
<div className="flex flex-col">
{sortColumn === column.columnName ? (
sortDirection === "asc" ? (
<ArrowUp className="h-3 w-3" />
) : (
<ArrowDown className="h-3 w-3" />
)
) : (
<ArrowUpDown className="h-3 w-3 text-gray-400" />
)}
</div>
)}
</div>
)}
</th>
))}
</tr>
</thead>
<tbody>
{data.length === 0 ? (
<tr>
<td colSpan={columnsByPosition.normal.length} className="py-8 text-center text-gray-500">
{columnsByPosition.leftFixed.length === 0 && columnsByPosition.rightFixed.length === 0
? "데이터가 없습니다"
: ""}
</td>
</tr>
) : (
data.map((row, index) => (
<tr
key={`normal-row-${index}`}
className={cn(
"cursor-pointer border-b",
tableConfig.tableStyle?.hoverEffect && "hover:bg-gray-50",
tableConfig.tableStyle?.alternateRows && index % 2 === 1 && "bg-gray-50/50",
)}
onClick={() => handleRowClick(row)}
>
{columnsByPosition.normal.map((column) => (
<td
key={`normal-cell-${column.columnName}`}
className={cn(
"h-12 px-4 py-3 align-middle text-sm whitespace-nowrap",
`text-${column.align}`,
)}
style={{ minHeight: "48px", height: "48px", verticalAlign: "middle" }}
>
{column.columnName === "__checkbox__"
? renderCheckboxCell(row, index)
: formatCellValue(row[column.columnName], column.format, column.columnName) || "\u00A0"}
</td>
))}
</tr>
))
)}
</tbody>
</table>
</div>
{/* 오른쪽 고정 컬럼 */}
{columnsByPosition.rightFixed.length > 0 && (
<div className="flex-shrink-0 border-l bg-gray-50/50">
<table
className="table-fixed-layout table-auto"
style={{ borderCollapse: "collapse", margin: 0, padding: 0 }}
>
<thead className={tableConfig.stickyHeader ? "sticky top-0 z-20 bg-white" : ""}>
<tr>
{columnsByPosition.rightFixed.map((column) => (
<th
key={`fixed-right-${column.columnName}`}
className={cn(
column.columnName === "__checkbox__"
? "h-12 border-b px-4 py-3 text-center align-middle"
: "h-12 cursor-pointer border-b px-4 py-3 text-left align-middle font-medium whitespace-nowrap text-gray-900 select-none",
`text-${column.align}`,
column.sortable && "hover:bg-gray-50",
// 숨김 컬럼 스타일 (디자인 모드에서만)
isDesignMode && column.hidden && "bg-gray-100/50 opacity-40",
)}
style={{
minWidth: `${getColumnWidth(column)}px`,
minHeight: "48px",
height: "48px",
verticalAlign: "middle",
lineHeight: "1",
boxSizing: "border-box",
}}
onClick={() => column.sortable && handleSort(column.columnName)}
>
{column.columnName === "__checkbox__" ? (
renderCheckboxHeader()
) : (
<div className="flex items-center space-x-1">
<span className="text-sm">{columnLabels[column.columnName] || column.displayName}</span>
{column.sortable && (
<div className="flex flex-col">
{sortColumn === column.columnName ? (
sortDirection === "asc" ? (
<ArrowUp className="h-3 w-3" />
) : (
<ArrowDown className="h-3 w-3" />
)
) : (
<ArrowUpDown className="h-3 w-3 text-gray-400" />
)}
</div>
)}
</div>
)}
</th>
))}
</tr>
</thead>
<tbody>
{data.length === 0 ? (
<tr>
<td colSpan={columnsByPosition.rightFixed.length} className="py-8 text-center text-gray-500">
{columnsByPosition.leftFixed.length === 0 && columnsByPosition.normal.length === 0
? "데이터가 없습니다"
: ""}
</td>
</tr>
) : (
data.map((row, index) => (
<tr
key={`fixed-right-row-${index}`}
className={cn(
"h-12 cursor-pointer border-b leading-none",
tableConfig.tableStyle?.hoverEffect && "hover:bg-gray-50",
tableConfig.tableStyle?.alternateRows && index % 2 === 1 && "bg-gray-50/50",
)}
style={{ minHeight: "48px", height: "48px", lineHeight: "1" }}
onClick={() => handleRowClick(row)}
>
{columnsByPosition.rightFixed.map((column) => (
<td
key={`fixed-right-cell-${column.columnName}`}
className={cn(
"h-12 px-4 py-3 align-middle text-sm whitespace-nowrap",
`text-${column.align}`,
)}
style={{ minHeight: "48px", height: "48px", verticalAlign: "middle" }}
>
{column.columnName === "__checkbox__"
? renderCheckboxCell(row, index)
: formatCellValue(row[column.columnName], column.format, column.columnName) || "\u00A0"}
</td>
))}
</tr>
))
)}
</tbody>
</table>
</div>
)}
</div>
) : ( ) : (
// 기존 테이블 (가로 스크롤이 필요 없는 경우) // 기존 테이블 (가로 스크롤이 필요 없는 경우)
<Table> <Table>
<TableHeader className={tableConfig.stickyHeader ? "sticky top-0 z-10 bg-white" : ""}> <TableHeader className={tableConfig.stickyHeader ? "sticky top-0 z-10 bg-white" : ""}>
<TableRow style={{ minHeight: "48px !important", height: "48px !important", lineHeight: "1" }}> <TableRow style={{ minHeight: "40px !important", height: "40px !important", lineHeight: "1" }}>
{visibleColumns.map((column) => ( {visibleColumns.map((column) => (
<TableHead <TableHead
key={column.columnName} key={column.columnName}
style={{ style={{
width: column.width ? `${column.width}px` : undefined, width: column.width ? `${column.width}px` : undefined,
minHeight: "48px !important", minHeight: "40px !important",
height: "48px !important", height: "40px !important",
verticalAlign: "middle", verticalAlign: "middle",
lineHeight: "1", lineHeight: "1",
boxSizing: "border-box", boxSizing: "border-box",
}} }}
className={cn( className={cn(
column.columnName === "__checkbox__" column.columnName === "__checkbox__"
? "h-12 text-center align-middle" ? "h-10 text-center align-middle"
: "h-12 cursor-pointer align-middle whitespace-nowrap select-none", : "h-10 cursor-pointer align-middle whitespace-nowrap select-none",
`text-${column.align}`, `text-${column.align}`,
column.sortable && "hover:bg-gray-50", column.sortable && "hover:bg-gray-50",
)} )}
@ -1286,18 +1021,18 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
<TableRow <TableRow
key={index} key={index}
className={cn( className={cn(
"h-12 cursor-pointer leading-none", "h-10 cursor-pointer leading-none",
tableConfig.tableStyle?.hoverEffect && "hover:bg-gray-50", tableConfig.tableStyle?.hoverEffect && "hover:bg-gray-50",
tableConfig.tableStyle?.alternateRows && index % 2 === 1 && "bg-gray-50/50", tableConfig.tableStyle?.alternateRows && index % 2 === 1 && "bg-gray-50/50",
)} )}
style={{ minHeight: "48px", height: "48px", lineHeight: "1" }} style={{ minHeight: "40px", height: "40px", lineHeight: "1" }}
onClick={() => handleRowClick(row)} onClick={() => handleRowClick(row)}
> >
{visibleColumns.map((column) => ( {visibleColumns.map((column) => (
<TableCell <TableCell
key={column.columnName} key={column.columnName}
className={cn("h-12 align-middle whitespace-nowrap", `text-${column.align}`)} className={cn("h-10 align-middle whitespace-nowrap", `text-${column.align}`)}
style={{ minHeight: "48px", height: "48px", verticalAlign: "middle" }} style={{ minHeight: "40px", height: "40px", verticalAlign: "middle" }}
> >
{column.columnName === "__checkbox__" {column.columnName === "__checkbox__"
? renderCheckboxCell(row, index) ? renderCheckboxCell(row, index)