ERP-node/frontend/lib/registry/components/repeat-screen-modal/README.md

15 KiB

RepeatScreenModal 컴포넌트 v3.1

개요

RepeatScreenModal은 선택한 데이터를 기반으로 여러 개의 카드를 생성하고, 각 카드의 내부 레이아웃을 자유롭게 구성할 수 있는 컴포넌트입니다.

v3.1 주요 변경사항 (2025-11-28)

1. 외부 테이블 데이터 소스

테이블 행에서 외부 테이블의 데이터를 조회하여 표시할 수 있습니다.

예시: 수주 관리에서 출하 계획 이력 조회
┌─────────────────────────────────────────────────────────────────┐
│ 카드: 품목 A                                                     │
├─────────────────────────────────────────────────────────────────┤
│ [행 1] 헤더: 품목코드, 품목명                                    │
├─────────────────────────────────────────────────────────────────┤
│ [행 2] 테이블: shipment_plan 테이블에서 조회                     │
│        → sales_order_id로 조인하여 출하 계획 이력 표시           │
└─────────────────────────────────────────────────────────────────┘

2. 테이블 행 CRUD

테이블 행에서 행 추가/수정/삭제 기능을 지원합니다.

  • 추가: 새 행 추가 버튼으로 빈 행 생성
  • 수정: 편집 가능한 컬럼 직접 수정
  • 삭제: 행 삭제 (확인 팝업 옵션)

모달 하단에 커스터마이징 가능한 버튼 영역을 제공합니다.

┌─────────────────────────────────────────────────────────────────┐
│ 카드 내용...                                                     │
├─────────────────────────────────────────────────────────────────┤
│                                    [초기화] [취소] [저장]        │
└─────────────────────────────────────────────────────────────────┘

4. 집계 연산식 지원

집계 행에서 컬럼 간 사칙연산을 지원합니다.

// 예: 미출하 수량 = 수주수량 - 출하수량
{
  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 신규)
    • 추가: 새 행 추가 허용
    • 수정: 행 수정 허용
    • 삭제: 행 삭제 허용 (확인 팝업 옵션)
  • 테이블 컬럼: 필드명, 라벨, 타입, 너비, 편집 가능
  • 저장 설정: 편집 가능한 컬럼의 저장 위치
  • 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)

{
  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

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

interface TableCrudConfig {
  allowCreate: boolean;       // 행 추가 허용
  allowUpdate: boolean;       // 행 수정 허용
  allowDelete: boolean;       // 행 삭제 허용
  newRowDefaults?: Record<string, string>; // 신규 행 기본값 ({field} 형식 지원)
  deleteConfirm?: {
    enabled: boolean;         // 삭제 확인 팝업
    message?: string;         // 확인 메시지
  };
  targetTable?: string;       // 저장 대상 테이블
}

FooterConfig

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<string, any>;
  };
}

AggregationDisplayConfig (v3.1 확장)

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 분리