# RepeatScreenModal 컴포넌트 v3.1 ## 개요 `RepeatScreenModal`은 선택한 데이터를 기반으로 여러 개의 카드를 생성하고, 각 카드의 내부 레이아웃을 자유롭게 구성할 수 있는 컴포넌트입니다. ## v3.1 주요 변경사항 (2025-11-28) ### 1. 외부 테이블 데이터 소스 테이블 행에서 **외부 테이블의 데이터를 조회**하여 표시할 수 있습니다. ``` 예시: 수주 관리에서 출하 계획 이력 조회 ┌─────────────────────────────────────────────────────────────────┐ │ 카드: 품목 A │ ├─────────────────────────────────────────────────────────────────┤ │ [행 1] 헤더: 품목코드, 품목명 │ ├─────────────────────────────────────────────────────────────────┤ │ [행 2] 테이블: shipment_plan 테이블에서 조회 │ │ → sales_order_id로 조인하여 출하 계획 이력 표시 │ └─────────────────────────────────────────────────────────────────┘ ``` ### 2. 테이블 행 CRUD 테이블 행에서 **행 추가/수정/삭제** 기능을 지원합니다. - **추가**: 새 행 추가 버튼으로 빈 행 생성 - **수정**: 편집 가능한 컬럼 직접 수정 - **삭제**: 행 삭제 (확인 팝업 옵션) ### 3. Footer 버튼 영역 모달 하단에 **커스터마이징 가능한 버튼 영역**을 제공합니다. ``` ┌─────────────────────────────────────────────────────────────────┐ │ 카드 내용... │ ├─────────────────────────────────────────────────────────────────┤ │ [초기화] [취소] [저장] │ └─────────────────────────────────────────────────────────────────┘ ``` ### 4. 집계 연산식 지원 집계 행에서 **컬럼 간 사칙연산**을 지원합니다. ```typescript // 예: 미출하 수량 = 수주수량 - 출하수량 { sourceType: "formula", formula: "{order_qty} - {ship_qty}", label: "미출하 수량" } ``` --- ## v3 주요 변경사항 (기존) ### 자유 레이아웃 시스템 기존의 "simple 모드 / withTable 모드" 구분을 없애고, **행(Row)을 추가하고 각 행마다 타입을 선택**하는 방식으로 변경되었습니다. ``` ┌─────────────────────────────────────────────────────────────────┐ │ 카드 │ ├─────────────────────────────────────────────────────────────────┤ │ [행 1] 타입: 헤더 → 품목코드, 품목명, 규격 │ ├─────────────────────────────────────────────────────────────────┤ │ [행 2] 타입: 집계 → 총수주잔량, 현재고, 가용재고 │ ├─────────────────────────────────────────────────────────────────┤ │ [행 3] 타입: 테이블 → 수주번호, 거래처, 납기일, 출하계획 │ ├─────────────────────────────────────────────────────────────────┤ │ [행 4] 타입: 테이블 → 또 다른 테이블도 가능! │ └─────────────────────────────────────────────────────────────────┘ ``` ### 행 타입 | 타입 | 설명 | 사용 시나리오 | |------|------|---------------| | **헤더 (header)** | 필드들을 가로/세로로 나열 | 품목정보, 거래처정보 표시 | | **필드 (fields)** | 헤더와 동일, 편집 가능 | 폼 입력 영역 | | **집계 (aggregation)** | 그룹 내 데이터 집계값 표시 | 총수량, 합계금액 등 | | **테이블 (table)** | 그룹 내 각 행을 테이블로 표시 | 수주목록, 품목목록 등 | --- ## 설정 방법 ### 1. 기본 설정 탭 - **카드 제목 표시**: 카드 상단에 제목을 표시할지 여부 - **카드 제목 템플릿**: `{field_name}` 형식으로 동적 제목 생성 - **카드 간격**: 카드 사이의 간격 (8px ~ 32px) - **테두리**: 카드 테두리 표시 여부 - **저장 모드**: 전체 저장 / 개별 저장 ### 2. 데이터 소스 탭 - **소스 테이블**: 데이터를 조회할 테이블 - **필터 필드**: formData에서 필터링할 필드 (예: selectedIds) ### 3. 그룹 탭 - **그룹핑 활성화**: 여러 행을 하나의 카드로 묶을지 여부 - **그룹 기준 필드**: 그룹핑할 필드 (예: part_code) - **집계 설정**: - 원본 필드: 합계할 필드 (예: balance_qty) - 집계 타입: sum, count, avg, min, max - 결과 필드명: 집계 결과를 저장할 필드명 - 라벨: 표시될 라벨 ### 4. 레이아웃 탭 #### 행 추가 4가지 타입의 행을 추가할 수 있습니다: - **헤더**: 필드 정보 표시 (읽기전용) - **집계**: 그룹 집계값 표시 - **테이블**: 그룹 내 행들을 테이블로 표시 - **필드**: 입력 필드 (편집가능) #### 헤더/필드 행 설정 - **방향**: 가로 / 세로 - **배경색**: 없음, 파랑, 초록, 보라, 주황 - **컬럼**: 필드명, 라벨, 타입, 너비, 편집 가능, 필수 - **소스 설정**: 직접 / 조인 / 수동 - **저장 설정**: 저장할 테이블과 컬럼 #### 집계 행 설정 - **레이아웃**: 가로 나열 / 그리드 - **그리드 컬럼 수**: 2, 3, 4개 - **집계 필드**: 그룹 탭에서 정의한 집계 결과 선택 - **스타일**: 배경색, 폰트 크기 #### 테이블 행 설정 (v3.1 확장) - **테이블 제목**: 선택사항 - **헤더 표시**: 테이블 헤더 표시 여부 - **외부 테이블 데이터 소스**: (v3.1 신규) - 소스 테이블: 조회할 외부 테이블 - 조인 조건: 외부 테이블 키 ↔ 카드 데이터 키 - 정렬: 정렬 컬럼 및 방향 - **CRUD 설정**: (v3.1 신규) - 추가: 새 행 추가 허용 - 수정: 행 수정 허용 - 삭제: 행 삭제 허용 (확인 팝업 옵션) - **테이블 컬럼**: 필드명, 라벨, 타입, 너비, 편집 가능 - **저장 설정**: 편집 가능한 컬럼의 저장 위치 ### 5. Footer 탭 (v3.1 신규) - **Footer 사용**: Footer 영역 활성화 - **위치**: 컨텐츠 아래 / 하단 고정 (sticky) - **정렬**: 왼쪽 / 가운데 / 오른쪽 - **버튼 설정**: - 라벨: 버튼 텍스트 - 액션: 저장 / 취소 / 닫기 / 초기화 / 커스텀 - 스타일: 기본 / 보조 / 외곽선 / 삭제 / 고스트 - 아이콘: 저장 / X / 초기화 / 없음 --- ## 데이터 흐름 ``` 1. formData에서 selectedIds 가져오기 ↓ 2. 소스 테이블에서 해당 ID들의 데이터 조회 ↓ 3. 그룹핑 활성화 시 groupByField 기준으로 그룹화 ↓ 4. 각 그룹에 대해 집계값 계산 ↓ 5. 외부 테이블 데이터 소스가 설정된 테이블 행의 데이터 로드 (v3.1) ↓ 6. 카드 렌더링 (contentRows 기반) ↓ 7. 사용자 편집 (CRUD 포함) ↓ 8. Footer 버튼 또는 기본 저장 버튼으로 저장 ↓ 9. 기본 데이터 + 외부 테이블 데이터 일괄 저장 ``` --- ## 사용 예시 ### 출하계획 등록 (v3.1 - 외부 테이블 + CRUD) ```typescript { showCardTitle: true, cardTitle: "{part_code} - {part_name}", dataSource: { sourceTable: "sales_order_mng", filterField: "selectedIds" }, grouping: { enabled: true, groupByField: "part_code", aggregations: [ { sourceField: "balance_qty", type: "sum", resultField: "total_balance", label: "총수주잔량" }, { sourceField: "id", type: "count", resultField: "order_count", label: "수주건수" } ] }, contentRows: [ { id: "row-1", type: "header", columns: [ { id: "c1", field: "part_code", label: "품목코드", type: "text", editable: false }, { id: "c2", field: "part_name", label: "품목명", type: "text", editable: false } ], layout: "horizontal" }, { id: "row-2", type: "aggregation", aggregationLayout: "horizontal", aggregationFields: [ { sourceType: "aggregation", aggregationResultField: "total_balance", label: "총수주잔량", backgroundColor: "blue" }, { sourceType: "formula", formula: "{order_qty} - {ship_qty}", label: "미출하 수량", backgroundColor: "orange" } ] }, { id: "row-3", type: "table", tableTitle: "출하 계획 이력", showTableHeader: true, // 외부 테이블에서 데이터 조회 tableDataSource: { enabled: true, sourceTable: "shipment_plan", joinConditions: [ { sourceKey: "sales_order_id", referenceKey: "id" } ], orderBy: { column: "created_date", direction: "desc" } }, // CRUD 설정 tableCrud: { allowCreate: true, allowUpdate: true, allowDelete: true, newRowDefaults: { sales_order_id: "{id}", status: "READY" }, deleteConfirm: { enabled: true } }, tableColumns: [ { id: "tc1", field: "plan_date", label: "계획일", type: "date", editable: true }, { id: "tc2", field: "plan_qty", label: "계획수량", type: "number", editable: true }, { id: "tc3", field: "status", label: "상태", type: "text", editable: false }, { id: "tc4", field: "memo", label: "비고", type: "text", editable: true } ] } ], // Footer 설정 footerConfig: { enabled: true, position: "sticky", alignment: "right", buttons: [ { id: "btn-cancel", label: "취소", action: "cancel", variant: "outline" }, { id: "btn-save", label: "저장", action: "save", variant: "default", icon: "save" } ] } } ``` --- ## 타입 정의 (v3.1) ### TableDataSourceConfig ```typescript interface TableDataSourceConfig { enabled: boolean; // 외부 데이터 소스 사용 여부 sourceTable: string; // 조회할 테이블 joinConditions: JoinCondition[]; // 조인 조건 orderBy?: { column: string; // 정렬 컬럼 direction: "asc" | "desc"; // 정렬 방향 }; limit?: number; // 최대 행 수 } interface JoinCondition { sourceKey: string; // 외부 테이블의 조인 키 referenceKey: string; // 카드 데이터의 참조 키 referenceType?: "card" | "row"; // 참조 소스 } ``` ### TableCrudConfig ```typescript interface TableCrudConfig { allowCreate: boolean; // 행 추가 허용 allowUpdate: boolean; // 행 수정 허용 allowDelete: boolean; // 행 삭제 허용 newRowDefaults?: Record; // 신규 행 기본값 ({field} 형식 지원) deleteConfirm?: { enabled: boolean; // 삭제 확인 팝업 message?: string; // 확인 메시지 }; targetTable?: string; // 저장 대상 테이블 } ``` ### FooterConfig ```typescript interface FooterConfig { enabled: boolean; // Footer 사용 여부 buttons?: FooterButtonConfig[]; position?: "sticky" | "static"; alignment?: "left" | "center" | "right"; } interface FooterButtonConfig { id: string; label: string; action: "save" | "cancel" | "close" | "reset" | "custom"; variant?: "default" | "secondary" | "outline" | "destructive" | "ghost"; icon?: string; disabled?: boolean; customAction?: { type: string; config?: Record; }; } ``` ### AggregationDisplayConfig (v3.1 확장) ```typescript interface AggregationDisplayConfig { // 값 소스 타입 sourceType: "aggregation" | "formula" | "external" | "externalFormula"; // aggregation: 기존 집계 결과 참조 aggregationResultField?: string; // formula: 컬럼 간 연산 formula?: string; // 예: "{order_qty} - {ship_qty}" // external: 외부 테이블 조회 (향후 구현) externalSource?: ExternalValueSource; // externalFormula: 외부 테이블 + 연산 (향후 구현) externalSources?: ExternalValueSource[]; externalFormula?: string; // 표시 설정 label: string; icon?: string; backgroundColor?: string; textColor?: string; fontSize?: "xs" | "sm" | "base" | "lg" | "xl" | "2xl"; format?: "number" | "currency" | "percent"; decimalPlaces?: number; } ``` --- ## 레거시 호환 v2에서 사용하던 `cardMode`, `cardLayout`, `tableLayout` 설정도 계속 지원됩니다. 새로운 프로젝트에서는 `contentRows`를 사용하는 것을 권장합니다. --- ## 주의사항 1. **집계는 그룹핑 필수**: 집계 행은 그룹핑이 활성화되어 있어야 의미가 있습니다. 2. **테이블은 그룹핑 필수**: 테이블 행도 그룹핑이 활성화되어 있어야 그룹 내 행들을 표시할 수 있습니다. 3. **단순 모드**: 그룹핑 없이 사용하면 1행 = 1카드로 동작합니다. 이 경우 헤더/필드 타입만 사용 가능합니다. 4. **외부 테이블 CRUD**: 외부 테이블 데이터 소스가 설정된 테이블에서만 CRUD가 동작합니다. 5. **연산식**: 사칙연산(+, -, *, /)과 괄호만 지원됩니다. 복잡한 함수는 지원하지 않습니다. --- ## 변경 이력 ### v3.1 (2025-11-28) - 외부 테이블 데이터 소스 기능 추가 - 테이블 행 CRUD (추가/수정/삭제) 기능 추가 - Footer 버튼 영역 기능 추가 - 집계 연산식 (formula) 지원 추가 - 다단계 조인 타입 정의 추가 (향후 구현 예정) ### v3.0 - 자유 레이아웃 시스템 도입 - contentRows 기반 행 타입 선택 방식 - 헤더/필드/집계/테이블 4가지 행 타입 지원 ### v2.0 - simple 모드 / withTable 모드 구분 - cardLayout / tableLayout 분리