616 lines
14 KiB
Markdown
616 lines
14 KiB
Markdown
|
|
# SAM MES 테이블 디자인 시스템
|
||
|
|
|
||
|
|
> **작성일**: 2025년 10월 24일
|
||
|
|
> **버전**: 1.0.0
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📋 목차
|
||
|
|
|
||
|
|
1. [개요](#개요)
|
||
|
|
2. [테이블 시스템 구조](#테이블-시스템-구조)
|
||
|
|
3. [셀 타입](#셀-타입)
|
||
|
|
4. [컴포넌트 가이드](#컴포넌트-가이드)
|
||
|
|
5. [사용 예시](#사용-예시)
|
||
|
|
6. [Best Practices](#best-practices)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 개요
|
||
|
|
|
||
|
|
SAM MES의 모든 테이블은 통일된 디자인 시스템을 사용합니다. 컬럼과 데이터만 정의하면 자동으로 적절한 형태로 렌더링됩니다.
|
||
|
|
|
||
|
|
### 핵심 원칙
|
||
|
|
|
||
|
|
1. **일관성**: 모든 테이블이 동일한 디자인 패턴
|
||
|
|
2. **타입 안정성**: 셀 타입별 자동 렌더링
|
||
|
|
3. **재사용성**: 컬럼 정의만으로 테이블 완성
|
||
|
|
4. **반응형**: 데스크톱/모바일 자동 대응
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 테이블 시스템 구조
|
||
|
|
|
||
|
|
```
|
||
|
|
DataTable (Organism)
|
||
|
|
├── Column Definition (셀 타입 정의)
|
||
|
|
├── Cell Renderer (타입별 자동 렌더링)
|
||
|
|
│ ├── StatusBadge (Molecule)
|
||
|
|
│ ├── IconWithBadge (Molecule)
|
||
|
|
│ ├── TableActions (Molecule)
|
||
|
|
│ └── Badge (Atom)
|
||
|
|
└── Pagination (Optional)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 셀 타입
|
||
|
|
|
||
|
|
### 지원하는 셀 타입
|
||
|
|
|
||
|
|
| 타입 | 설명 | 정렬 | 예시 |
|
||
|
|
|------|------|------|------|
|
||
|
|
| **text** | 일반 텍스트 | 좌측 | "홍길동" |
|
||
|
|
| **number** | 숫자 (자동 천 단위 구분) | 우측 | 1,234 |
|
||
|
|
| **currency** | 통화 (₩ 표시) | 우측 | ₩1,234,567 |
|
||
|
|
| **date** | 날짜 | 좌측 | 2025-10-24 |
|
||
|
|
| **datetime** | 날짜 + 시간 | 좌측 | 2025-10-24 14:30 |
|
||
|
|
| **status** | 상태 배지 | 중앙 | 🟢 활성 |
|
||
|
|
| **badge** | 일반 배지 | 중앙 | v1.0 |
|
||
|
|
| **icon** | 아이콘 | 중앙 | 📦 |
|
||
|
|
| **iconBadge** | 아이콘 + 배지 | 좌측 | 📦 완제품 |
|
||
|
|
| **actions** | 액션 버튼들 | 우측 | 👁️ ✏️ 🗑️ |
|
||
|
|
| **custom** | 커스텀 렌더링 | 설정 가능 | (사용자 정의) |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 컴포넌트 가이드
|
||
|
|
|
||
|
|
### 1. DataTable (Organism)
|
||
|
|
|
||
|
|
통일된 테이블 컴포넌트
|
||
|
|
|
||
|
|
**위치**: `/components/organisms/DataTable.tsx`
|
||
|
|
|
||
|
|
**Props**:
|
||
|
|
```typescript
|
||
|
|
interface DataTableProps<T> {
|
||
|
|
columns: Column<T>[]; // 컬럼 정의
|
||
|
|
data: T[]; // 데이터
|
||
|
|
keyField: keyof T; // 고유 키 필드
|
||
|
|
onRowClick?: (row: T) => void; // 행 클릭 핸들러
|
||
|
|
loading?: boolean; // 로딩 상태
|
||
|
|
emptyMessage?: string; // 빈 메시지
|
||
|
|
pagination?: { // 페이지네이션
|
||
|
|
currentPage: number;
|
||
|
|
totalPages: number;
|
||
|
|
onPageChange: (page: number) => void;
|
||
|
|
};
|
||
|
|
striped?: boolean; // 줄무늬 (기본: false)
|
||
|
|
hoverable?: boolean; // 호버 효과 (기본: true)
|
||
|
|
compact?: boolean; // 컴팩트 모드 (기본: false)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Column 정의**:
|
||
|
|
```typescript
|
||
|
|
interface Column<T> {
|
||
|
|
key: keyof T | string; // 데이터 키
|
||
|
|
label: string; // 컬럼 헤더
|
||
|
|
type?: CellType; // 셀 타입
|
||
|
|
width?: string; // 너비
|
||
|
|
align?: "left" | "center" | "right"; // 정렬
|
||
|
|
|
||
|
|
// 타입별 설정
|
||
|
|
statusConfig?: { showDot?: boolean };
|
||
|
|
badgeConfig?: { variant?: string; className?: string };
|
||
|
|
iconConfig?: { iconColor?: string; iconBgColor?: string; size?: "sm" | "md" | "lg" };
|
||
|
|
currencyConfig?: { locale?: string; currency?: string };
|
||
|
|
|
||
|
|
// 커스텀
|
||
|
|
render?: (value: any, row: T) => ReactNode;
|
||
|
|
format?: (value: any) => string | number;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 2. StatusBadge (Molecule)
|
||
|
|
|
||
|
|
상태 표시 배지
|
||
|
|
|
||
|
|
**위치**: `/components/molecules/StatusBadge.tsx`
|
||
|
|
|
||
|
|
**지원 상태**:
|
||
|
|
```typescript
|
||
|
|
// 프로세스 상태
|
||
|
|
"대기" | "진행중" | "완료" | "취소" | "반려"
|
||
|
|
|
||
|
|
// 문서 상태
|
||
|
|
"작성중" | "검토중" | "승인" | "보류"
|
||
|
|
|
||
|
|
// 품질 상태
|
||
|
|
"합격" | "부적합" | "조건부합격" | "검사중"
|
||
|
|
|
||
|
|
// 설비 상태
|
||
|
|
"정상" | "고장" | "점검중"
|
||
|
|
|
||
|
|
// 활성화 상태
|
||
|
|
"활성" | "비활성" | "사용" | "미사용" | "폐기"
|
||
|
|
|
||
|
|
// 생산 상태
|
||
|
|
"생산중" | "배송중" | "생산대기"
|
||
|
|
|
||
|
|
// 재고 상태
|
||
|
|
"입고" | "출고" | "재고부족"
|
||
|
|
```
|
||
|
|
|
||
|
|
**사용법**:
|
||
|
|
```typescript
|
||
|
|
<StatusBadge status="활성" />
|
||
|
|
<StatusBadge status="진행중" showDot />
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 3. IconWithBadge (Molecule)
|
||
|
|
|
||
|
|
아이콘 + 라벨 + 배지 조합
|
||
|
|
|
||
|
|
**위치**: `/components/molecules/IconWithBadge.tsx`
|
||
|
|
|
||
|
|
**사용법**:
|
||
|
|
```typescript
|
||
|
|
<IconWithBadge
|
||
|
|
icon={Package}
|
||
|
|
label="완제품"
|
||
|
|
iconColor="text-blue-600"
|
||
|
|
iconBgColor="bg-blue-100"
|
||
|
|
badge={{ label: "신규", variant: "default" }}
|
||
|
|
size="md"
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 4. TableActions (Molecule)
|
||
|
|
|
||
|
|
테이블 액션 버튼 그룹
|
||
|
|
|
||
|
|
**위치**: `/components/molecules/TableActions.tsx`
|
||
|
|
|
||
|
|
**지원 액션 타입**:
|
||
|
|
- `view` - 상세보기 (👁️)
|
||
|
|
- `edit` - 수정 (✏️)
|
||
|
|
- `delete` - 삭제 (🗑️)
|
||
|
|
- `copy` - 복사 (📋)
|
||
|
|
- `download` - 다운로드 (⬇️)
|
||
|
|
- `custom` - 커스텀
|
||
|
|
|
||
|
|
**레이아웃**:
|
||
|
|
- `buttons` - 버튼으로 표시
|
||
|
|
- `dropdown` - 드롭다운 메뉴
|
||
|
|
- `auto` - 자동 (3개 이하: 버튼, 4개 이상: 드롭다운)
|
||
|
|
|
||
|
|
**사용법**:
|
||
|
|
```typescript
|
||
|
|
<TableActions
|
||
|
|
actions={[
|
||
|
|
{ type: "view", onClick: handleView },
|
||
|
|
{ type: "edit", onClick: handleEdit },
|
||
|
|
{ type: "delete", onClick: handleDelete, variant: "destructive" }
|
||
|
|
]}
|
||
|
|
layout="auto"
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 사용 예시
|
||
|
|
|
||
|
|
### 예시 1: 기본 테이블
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
import { DataTable, Column } from "./organisms/DataTable";
|
||
|
|
|
||
|
|
interface Product {
|
||
|
|
id: string;
|
||
|
|
code: string;
|
||
|
|
name: string;
|
||
|
|
price: number;
|
||
|
|
status: string;
|
||
|
|
updatedAt: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
function ProductList() {
|
||
|
|
const columns: Column<Product>[] = [
|
||
|
|
{ key: "code", label: "제품코드", type: "text" },
|
||
|
|
{ key: "name", label: "제품명", type: "text" },
|
||
|
|
{ key: "price", label: "가격", type: "currency" },
|
||
|
|
{ key: "status", label: "상태", type: "status" },
|
||
|
|
{ key: "updatedAt", label: "수정일", type: "date" }
|
||
|
|
];
|
||
|
|
|
||
|
|
return (
|
||
|
|
<DataTable
|
||
|
|
columns={columns}
|
||
|
|
data={products}
|
||
|
|
keyField="id"
|
||
|
|
/>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 예시 2: 액션 버튼이 있는 테이블
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
const columns: Column<Product>[] = [
|
||
|
|
{ key: "code", label: "제품코드", type: "text" },
|
||
|
|
{ key: "name", label: "제품명", type: "text" },
|
||
|
|
{ key: "price", label: "가격", type: "currency" },
|
||
|
|
{ key: "status", label: "상태", type: "status" },
|
||
|
|
{
|
||
|
|
key: "id",
|
||
|
|
label: "관리",
|
||
|
|
type: "actions",
|
||
|
|
render: (_, row) => [
|
||
|
|
{ type: "view", onClick: () => handleView(row) },
|
||
|
|
{ type: "edit", onClick: () => handleEdit(row) },
|
||
|
|
{ type: "delete", onClick: () => handleDelete(row), variant: "destructive" }
|
||
|
|
]
|
||
|
|
}
|
||
|
|
];
|
||
|
|
```
|
||
|
|
|
||
|
|
### 예시 3: 아이콘 + 배지
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
const columns: Column<Item>[] = [
|
||
|
|
{
|
||
|
|
key: "type",
|
||
|
|
label: "품목유형",
|
||
|
|
type: "iconBadge",
|
||
|
|
render: (value) => ({
|
||
|
|
icon: getItemIcon(value),
|
||
|
|
label: getItemLabel(value),
|
||
|
|
badge: { label: "신규", variant: "default" }
|
||
|
|
})
|
||
|
|
}
|
||
|
|
];
|
||
|
|
```
|
||
|
|
|
||
|
|
### 예시 4: 커스텀 렌더링
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
const columns: Column<Order>[] = [
|
||
|
|
{
|
||
|
|
key: "customer",
|
||
|
|
label: "고객사",
|
||
|
|
type: "custom",
|
||
|
|
render: (value, row) => (
|
||
|
|
<div>
|
||
|
|
<p className="font-medium">{value}</p>
|
||
|
|
<p className="text-xs text-muted-foreground">{row.customerCode}</p>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
];
|
||
|
|
```
|
||
|
|
|
||
|
|
### 예시 5: 페이지네이션
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
const { currentPage, totalPages, paginatedData, goToPage } = usePagination(data, 10);
|
||
|
|
|
||
|
|
<DataTable
|
||
|
|
columns={columns}
|
||
|
|
data={paginatedData}
|
||
|
|
keyField="id"
|
||
|
|
pagination={{
|
||
|
|
currentPage,
|
||
|
|
totalPages,
|
||
|
|
onPageChange: goToPage
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
### 예시 6: 다양한 옵션
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
<DataTable
|
||
|
|
columns={columns}
|
||
|
|
data={data}
|
||
|
|
keyField="id"
|
||
|
|
striped // 줄무늬
|
||
|
|
compact // 컴팩트 모드
|
||
|
|
hoverable={false} // 호버 효과 비활성화
|
||
|
|
loading={isLoading} // 로딩 상태
|
||
|
|
emptyMessage="검색 결과가 없습니다."
|
||
|
|
onRowClick={handleRowClick} // 행 클릭
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Best Practices
|
||
|
|
|
||
|
|
### 1. 올바른 타입 선택
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// ✅ 좋은 예
|
||
|
|
{ key: "price", label: "가격", type: "currency" }
|
||
|
|
{ key: "quantity", label: "수량", type: "number" }
|
||
|
|
{ key: "status", label: "상태", type: "status" }
|
||
|
|
{ key: "createdAt", label: "생성일", type: "date" }
|
||
|
|
|
||
|
|
// ❌ 나쁜 예
|
||
|
|
{ key: "price", label: "가격", type: "text" } // 통화 형식 미적용
|
||
|
|
{ key: "status", label: "상태", type: "text" } // 배지 미적용
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. 액션 버튼 정리
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// ✅ 좋은 예 - 타입 시스템 활용
|
||
|
|
{
|
||
|
|
key: "id",
|
||
|
|
label: "관리",
|
||
|
|
type: "actions",
|
||
|
|
render: (_, row) => [
|
||
|
|
{ type: "view", onClick: () => handleView(row) },
|
||
|
|
{ type: "edit", onClick: () => handleEdit(row) },
|
||
|
|
{ type: "delete", onClick: () => handleDelete(row), variant: "destructive" }
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
// ❌ 나쁜 예 - 직접 구현
|
||
|
|
{
|
||
|
|
key: "id",
|
||
|
|
label: "관리",
|
||
|
|
render: (_, row) => (
|
||
|
|
<div className="flex gap-2">
|
||
|
|
<Button onClick={() => handleView(row)}>보기</Button>
|
||
|
|
<Button onClick={() => handleEdit(row)}>수정</Button>
|
||
|
|
<Button onClick={() => handleDelete(row)}>삭제</Button>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. 상태 통일
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// ✅ 좋은 예 - StatusBadge 활용
|
||
|
|
{ key: "status", label: "상태", type: "status" }
|
||
|
|
|
||
|
|
// ❌ 나쁜 예 - 직접 구현
|
||
|
|
{
|
||
|
|
key: "status",
|
||
|
|
render: (value) => (
|
||
|
|
<Badge className={value === "활성" ? "bg-green-100" : "bg-gray-100"}>
|
||
|
|
{value}
|
||
|
|
</Badge>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4. 정렬 기본값
|
||
|
|
|
||
|
|
타입별 자동 정렬을 활용하세요:
|
||
|
|
- **text**: 좌측 정렬
|
||
|
|
- **number**, **currency**, **actions**: 우측 정렬
|
||
|
|
- **status**, **badge**, **icon**: 중앙 정렬
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// ✅ 자동 정렬 활용
|
||
|
|
{ key: "price", label: "가격", type: "currency" } // 자동 우측 정렬
|
||
|
|
|
||
|
|
// ⚠️ 필요시에만 명시
|
||
|
|
{ key: "price", label: "가격", type: "currency", align: "left" } // 수동 좌측 정렬
|
||
|
|
```
|
||
|
|
|
||
|
|
### 5. 반응형 대응
|
||
|
|
|
||
|
|
데스크톱과 모바일을 함께 고려하세요:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// 데스크톱: DataTable
|
||
|
|
<DataTable
|
||
|
|
columns={columns}
|
||
|
|
data={data}
|
||
|
|
keyField="id"
|
||
|
|
/>
|
||
|
|
|
||
|
|
// 모바일: MobileCard
|
||
|
|
<div className="md:hidden space-y-3">
|
||
|
|
{data.map((item) => (
|
||
|
|
<MobileCard
|
||
|
|
key={item.id}
|
||
|
|
title={item.name}
|
||
|
|
subtitle={item.code}
|
||
|
|
fields={[...]}
|
||
|
|
/>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 마이그레이션 가이드
|
||
|
|
|
||
|
|
### 기존 테이블 → 새 테이블 시스템
|
||
|
|
|
||
|
|
**Before**:
|
||
|
|
```typescript
|
||
|
|
<Table>
|
||
|
|
<TableHeader>
|
||
|
|
<TableRow>
|
||
|
|
<TableHead>제품코드</TableHead>
|
||
|
|
<TableHead>제품명</TableHead>
|
||
|
|
<TableHead>가격</TableHead>
|
||
|
|
</TableRow>
|
||
|
|
</TableHeader>
|
||
|
|
<TableBody>
|
||
|
|
{data.map((row) => (
|
||
|
|
<TableRow key={row.id}>
|
||
|
|
<TableCell>{row.code}</TableCell>
|
||
|
|
<TableCell>{row.name}</TableCell>
|
||
|
|
<TableCell>₩{row.price.toLocaleString()}</TableCell>
|
||
|
|
</TableRow>
|
||
|
|
))}
|
||
|
|
</TableBody>
|
||
|
|
</Table>
|
||
|
|
```
|
||
|
|
|
||
|
|
**After**:
|
||
|
|
```typescript
|
||
|
|
const columns: Column<Product>[] = [
|
||
|
|
{ key: "code", label: "제품코드", type: "text" },
|
||
|
|
{ key: "name", label: "제품명", type: "text" },
|
||
|
|
{ key: "price", label: "가격", type: "currency" }
|
||
|
|
];
|
||
|
|
|
||
|
|
<DataTable columns={columns} data={data} keyField="id" />
|
||
|
|
```
|
||
|
|
|
||
|
|
**효과**:
|
||
|
|
- 코드 라인 수: 20+ 라인 → 5 라인 (75% 감소)
|
||
|
|
- 일관성: 자동으로 통일된 디자인 적용
|
||
|
|
- 유지보수: 컬럼 정의만 수정
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 컴포넌트 계층 구조
|
||
|
|
|
||
|
|
```
|
||
|
|
Atoms (UI 기본 컴포넌트)
|
||
|
|
├── Badge
|
||
|
|
├── Button
|
||
|
|
└── Table Components
|
||
|
|
|
||
|
|
Molecules (작은 조합)
|
||
|
|
├── StatusBadge ⭐ 상태 배지
|
||
|
|
├── IconWithBadge ⭐ 아이콘 + 배지
|
||
|
|
└── TableActions ⭐ 액션 버튼 그룹
|
||
|
|
|
||
|
|
Organisms (복잡한 조합)
|
||
|
|
└── DataTable ⭐ 통합 테이블
|
||
|
|
|
||
|
|
Templates (페이지 레이아웃)
|
||
|
|
└── ListPageTemplate ⭐ 목록 페이지 (DataTable 포함)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 적용 대상 페이지
|
||
|
|
|
||
|
|
### 즉시 적용 가능 (40개 이상)
|
||
|
|
|
||
|
|
**관리 페이지**:
|
||
|
|
- CustomerManagement
|
||
|
|
- SupplierManagement
|
||
|
|
- OrderManagement
|
||
|
|
- PurchaseOrderManagement
|
||
|
|
- ItemManagement
|
||
|
|
- EquipmentManagement
|
||
|
|
- VehicleManagement
|
||
|
|
- EmployeeManagement
|
||
|
|
- DepartmentManagement
|
||
|
|
|
||
|
|
**재고 관리**:
|
||
|
|
- InventoryManagement
|
||
|
|
- ReceivingManagement
|
||
|
|
- ShippingManagement
|
||
|
|
- StockStatus
|
||
|
|
|
||
|
|
**생산 관리**:
|
||
|
|
- ProductionManagement
|
||
|
|
- WorkOrderManagement
|
||
|
|
- ProcessManagement
|
||
|
|
|
||
|
|
**품질 관리**:
|
||
|
|
- IncomingInspectionManagement
|
||
|
|
- ProcessInspectionManagement
|
||
|
|
- FinalInspectionManagement
|
||
|
|
- NonconformingManagement
|
||
|
|
|
||
|
|
**회계/영업**:
|
||
|
|
- SalesAccountingManagement
|
||
|
|
- PurchaseAccountingManagement
|
||
|
|
- QuoteManagement
|
||
|
|
- PricingManagement
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## FAQ
|
||
|
|
|
||
|
|
### Q1. 커스텀 렌더링과 타입 시스템 중 어떤 것을 사용해야 하나요?
|
||
|
|
|
||
|
|
**A**: 가능하면 타입 시스템을 우선 사용하세요. 커스텀 렌더링은 정말 특수한 경우에만 사용합니다.
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// ✅ 타입 시스템 활용 (권장)
|
||
|
|
{ key: "status", label: "상태", type: "status" }
|
||
|
|
|
||
|
|
// ⚠️ 커스텀 렌더링 (특수한 경우만)
|
||
|
|
{
|
||
|
|
key: "complex",
|
||
|
|
render: (value, row) => (
|
||
|
|
<div>
|
||
|
|
<p>{value}</p>
|
||
|
|
<p className="text-xs">{row.detail}</p>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Q2. 액션 버튼이 4개 이상일 때 어떻게 표시되나요?
|
||
|
|
|
||
|
|
**A**: 자동으로 드롭다운 메뉴로 변환됩니다.
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// 3개 이하: 버튼으로 표시
|
||
|
|
// 4개 이상: 자동으로 드롭다운 메뉴로 변환
|
||
|
|
layout="auto" // 기본값
|
||
|
|
```
|
||
|
|
|
||
|
|
### Q3. 테이블 행을 클릭 가능하게 만들려면?
|
||
|
|
|
||
|
|
**A**: `onRowClick` prop을 사용하세요.
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
<DataTable
|
||
|
|
columns={columns}
|
||
|
|
data={data}
|
||
|
|
keyField="id"
|
||
|
|
onRowClick={(row) => navigate(`/detail/${row.id}`)}
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
### Q4. 로딩 상태는 어떻게 표시하나요?
|
||
|
|
|
||
|
|
**A**: `loading` prop을 사용하세요.
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
<DataTable
|
||
|
|
columns={columns}
|
||
|
|
data={data}
|
||
|
|
keyField="id"
|
||
|
|
loading={isLoading}
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 변경 이력
|
||
|
|
|
||
|
|
| 버전 | 날짜 | 변경 내용 |
|
||
|
|
|------|------|-----------|
|
||
|
|
| 1.0.0 | 2025-10-24 | 초기 버전 생성 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**문서 버전**: 1.0.0
|
||
|
|
**최종 업데이트**: 2025년 10월 24일
|
||
|
|
**작성자**: SAM MES 개발팀
|