249 lines
7.2 KiB
Markdown
249 lines
7.2 KiB
Markdown
|
|
# 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의 데이터가 자동으로 정리됩니다.
|
|||
|
|
|
|||
|
|
## 향후 개선 사항
|
|||
|
|
|
|||
|
|
- [ ] 일괄 수정 기능 (모든 항목에 같은 값 적용)
|
|||
|
|
- [ ] 엑셀 업로드로 일괄 입력
|
|||
|
|
- [ ] 조건부 필드 표시 (특정 조건에서만 필드 활성화)
|
|||
|
|
- [ ] 커스텀 검증 규칙
|
|||
|
|
- [ ] 실시간 계산 필드 (단가 × 수량 = 금액)
|