ERP-node/frontend/lib/registry/components/selected-items-detail-input/README.md

249 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SelectedItemsDetailInput 컴포넌트
선택된 항목들의 상세 정보를 입력하는 컴포넌트입니다.
## 개요
이 컴포넌트는 다음과 같은 흐름에서 사용됩니다:
1. **첫 번째 모달**: TableList에서 여러 항목 선택 (체크박스)
2. **버튼 클릭**: "다음" 버튼 클릭 → 선택된 데이터를 modalDataStore에 저장
3. **두 번째 모달**: SelectedItemsDetailInput이 자동으로 데이터를 읽어와서 표시
4. **추가 입력**: 각 항목별로 추가 정보 입력 (거래처 품번, 단가 등)
5. **저장**: 모든 데이터를 백엔드로 일괄 전송
## 주요 기능
- ✅ 전달받은 원본 데이터 표시 (읽기 전용)
- ✅ 각 항목별 추가 입력 필드 제공
- ✅ Grid/Table 레이아웃 또는 Card 레이아웃 지원
- ✅ 필드별 타입 지정 (text, number, date, select, checkbox, textarea)
- ✅ 필수 입력 검증
- ✅ 항목 삭제 기능 (선택적)
## 사용 방법
### 1단계: 첫 번째 모달 (품목 선택)
```tsx
// TableList 컴포넌트 설정
{
type: "table-list",
config: {
selectedTable: "item_info",
multiSelect: true, // 다중 선택 활성화
columns: [
{ columnName: "item_code", label: "품목코드" },
{ columnName: "item_name", label: "품목명" },
{ columnName: "spec", label: "규격" },
{ columnName: "unit", label: "단위" },
{ columnName: "price", label: "단가" }
]
}
}
// "다음" 버튼 설정
{
type: "button-primary",
config: {
text: "다음 (상세정보 입력)",
action: {
type: "openModalWithData", // 새 액션 타입
targetScreenId: "123", // 두 번째 모달 화면 ID
dataSourceId: "table-list-456" // TableList 컴포넌트 ID
}
}
}
```
### 2단계: 두 번째 모달 (상세 입력)
```tsx
// SelectedItemsDetailInput 컴포넌트 설정
{
type: "selected-items-detail-input",
config: {
dataSourceId: "table-list-456", // 첫 번째 모달의 TableList ID
targetTable: "sales_detail", // 최종 저장 테이블
layout: "grid", // 테이블 형식
// 전달받은 원본 데이터 중 표시할 컬럼
displayColumns: ["item_code", "item_name", "spec", "unit"],
// 추가 입력 필드 정의
additionalFields: [
{
name: "customer_item_code",
label: "거래처 품번",
type: "text",
required: false
},
{
name: "customer_item_name",
label: "거래처 품명",
type: "text",
required: false
},
{
name: "year",
label: "연도",
type: "select",
required: true,
options: [
{ value: "2024", label: "2024년" },
{ value: "2025", label: "2025년" }
]
},
{
name: "currency",
label: "통화단위",
type: "select",
required: true,
options: [
{ value: "KRW", label: "KRW (원)" },
{ value: "USD", label: "USD (달러)" }
]
},
{
name: "unit_price",
label: "단가",
type: "number",
required: true
},
{
name: "quantity",
label: "수량",
type: "number",
required: true
}
],
showIndex: true,
allowRemove: true // 항목 삭제 허용
}
}
```
### 3단계: 저장 버튼
```tsx
{
type: "button-primary",
config: {
text: "저장",
action: {
type: "save",
targetTable: "sales_detail",
// formData에 selected_items 데이터가 자동으로 포함됨
}
}
}
```
## 데이터 구조
### 전달되는 데이터 형식
```typescript
const modalData: ModalDataItem[] = [
{
id: "SALE-003", // 항목 ID
originalData: { // 원본 데이터 (TableList에서 선택한 행)
item_code: "SALE-003",
item_name: "와셔 M8",
spec: "M8",
unit: "EA",
price: 50
},
additionalData: { // 사용자가 입력한 추가 데이터
customer_item_code: "ABC-001",
customer_item_name: "와셔",
year: "2025",
currency: "KRW",
unit_price: 50,
quantity: 100
}
},
// ... 더 많은 항목들
];
```
## 설정 옵션
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `dataSourceId` | string | - | 데이터를 전달하는 컴포넌트 ID (필수) |
| `displayColumns` | string[] | [] | 표시할 원본 데이터 컬럼명 |
| `additionalFields` | AdditionalFieldDefinition[] | [] | 추가 입력 필드 정의 |
| `targetTable` | string | - | 최종 저장 대상 테이블 |
| `layout` | "grid" \| "card" | "grid" | 레이아웃 모드 |
| `showIndex` | boolean | true | 항목 번호 표시 여부 |
| `allowRemove` | boolean | false | 항목 삭제 허용 여부 |
| `emptyMessage` | string | "전달받은 데이터가 없습니다." | 빈 상태 메시지 |
| `disabled` | boolean | false | 비활성화 여부 |
| `readonly` | boolean | false | 읽기 전용 여부 |
## 추가 필드 정의
```typescript
interface AdditionalFieldDefinition {
name: string; // 필드명 (컬럼명)
label: string; // 필드 라벨
type: "text" | "number" | "date" | "select" | "checkbox" | "textarea";
required?: boolean; // 필수 입력 여부
placeholder?: string; // 플레이스홀더
defaultValue?: any; // 기본값
options?: Array<{ label: string; value: string }>; // 선택 옵션 (select 타입일 때)
validation?: { // 검증 규칙
min?: number;
max?: number;
minLength?: number;
maxLength?: number;
pattern?: string;
};
}
```
## 실전 예시: 수주 등록 화면
### 시나리오
1. 품목 선택 모달에서 여러 품목 선택
2. "다음" 버튼 클릭
3. 각 품목별로 거래처 정보, 단가, 수량 입력
4. "저장" 버튼으로 일괄 저장
### 구현
```tsx
// [모달 1] 품목 선택
<TableList id="item-selection-table" multiSelect={true} />
<Button action="openModalWithData" targetScreenId="detail-input-modal" dataSourceId="item-selection-table" />
// [모달 2] 상세 입력
<SelectedItemsDetailInput
dataSourceId="item-selection-table"
displayColumns={["item_code", "item_name", "spec"]}
additionalFields={[
{ name: "customer_item_code", label: "거래처 품번", type: "text" },
{ name: "unit_price", label: "단가", type: "number", required: true },
{ name: "quantity", label: "수량", type: "number", required: true }
]}
targetTable="sales_detail"
/>
<Button action="save" />
```
## 주의사항
1. **dataSourceId 일치**: 첫 번째 모달의 TableList ID와 두 번째 모달의 dataSourceId가 정확히 일치해야 합니다.
2. **컬럼명 정확성**: displayColumns와 additionalFields의 name은 실제 데이터베이스 컬럼명과 일치해야 합니다.
3. **필수 필드 검증**: required=true인 필드는 반드시 입력해야 저장이 가능합니다.
4. **데이터 정리**: 모달이 닫힐 때 modalDataStore의 데이터가 자동으로 정리됩니다.
## 향후 개선 사항
- [ ] 일괄 수정 기능 (모든 항목에 같은 값 적용)
- [ ] 엑셀 업로드로 일괄 입력
- [ ] 조건부 필드 표시 (특정 조건에서만 필드 활성화)
- [ ] 커스텀 검증 규칙
- [ ] 실시간 계산 필드 (단가 × 수량 = 금액)