feat: 레이어 시스템 추가 및 관리 기능 구현

- InteractiveScreenViewer 컴포넌트에 레이어 시스템을 도입하여, 레이어의 활성화 및 조건부 표시 로직을 추가하였습니다.
- ScreenDesigner 컴포넌트에서 레이어 상태 관리 및 레이어 정보 저장 기능을 구현하였습니다.
- 레이어 정의 및 조건부 표시 설정을 위한 새로운 타입과 스키마를 추가하여, 레이어 기반의 UI 구성 요소를 보다 유연하게 관리할 수 있도록 하였습니다.
- 레이어별 컴포넌트 렌더링 로직을 추가하여, 모달 및 드로어 형태의 레이어를 효과적으로 처리할 수 있도록 개선하였습니다.
- 전반적으로 레이어 시스템을 통해 사용자 경험을 향상시키고, UI 구성의 유연성을 높였습니다.
This commit is contained in:
kjs
2026-02-06 09:51:29 +09:00
parent e31bb970a2
commit 4e2209bd5d
8 changed files with 1336 additions and 144 deletions
+107 -45
View File
@@ -38,6 +38,9 @@ export interface BaseComponent {
gridColumnStart?: number; // 시작 컬럼 (1-12)
gridRowIndex?: number; // 행 인덱스
// 🆕 레이어 시스템
layerId?: string; // 컴포넌트가 속한 레이어 ID
parentId?: string;
label?: string;
required?: boolean;
@@ -102,13 +105,13 @@ export interface WidgetComponent extends BaseComponent {
entityConfig?: EntityTypeConfig;
buttonConfig?: ButtonTypeConfig;
arrayConfig?: ArrayTypeConfig;
// 🆕 자동 입력 설정 (테이블 조회 기반)
autoFill?: {
enabled: boolean; // 자동 입력 활성화
sourceTable: string; // 조회할 테이블 (예: company_mng)
filterColumn: string; // 필터링할 컬럼 (예: company_code)
userField: 'companyCode' | 'userId' | 'deptCode'; // 사용자 정보 필드
userField: "companyCode" | "userId" | "deptCode"; // 사용자 정보 필드
displayColumn: string; // 표시할 컬럼 (예: company_name)
};
}
@@ -148,12 +151,12 @@ export interface DataTableComponent extends BaseComponent {
searchable?: boolean;
sortable?: boolean;
filters?: DataTableFilter[];
// 🆕 현재 사용자 정보로 자동 필터링
autoFilter?: {
enabled: boolean; // 자동 필터 활성화 여부
filterColumn: string; // 필터링할 테이블 컬럼 (예: company_code, dept_code)
userField: 'companyCode' | 'userId' | 'deptCode'; // 사용자 정보에서 가져올 필드
userField: "companyCode" | "userId" | "deptCode"; // 사용자 정보에서 가져올 필드
};
// 🆕 컬럼 값 기반 데이터 필터링
@@ -307,13 +310,13 @@ export interface SelectTypeConfig {
required?: boolean;
readonly?: boolean;
emptyMessage?: string;
/** 🆕 연쇄 드롭다운 관계 코드 (관계 관리에서 정의한 코드) */
cascadingRelationCode?: string;
/** 🆕 연쇄 드롭다운 부모 필드명 (화면 내 다른 필드의 columnName) */
cascadingParentField?: string;
/** @deprecated 직접 설정 방식 - cascadingRelationCode 사용 권장 */
cascading?: CascadingDropdownConfig;
}
@@ -402,10 +405,10 @@ export interface EntityTypeConfig {
/**
* 🆕 연쇄 드롭다운(Cascading Dropdown) 설정
*
*
* 부모 필드의 값에 따라 자식 드롭다운의 옵션이 동적으로 변경됩니다.
* 예: 창고 선택 → 해당 창고의 위치만 표시
*
*
* @example
* // 창고 → 위치 연쇄 드롭다운
* {
@@ -420,34 +423,34 @@ export interface EntityTypeConfig {
export interface CascadingDropdownConfig {
/** 연쇄 드롭다운 활성화 여부 */
enabled: boolean;
/** 부모 필드명 (이 필드의 값에 따라 옵션이 필터링됨) */
parentField: string;
/** 옵션을 조회할 테이블명 */
sourceTable: string;
/** 부모 값과 매칭할 컬럼명 (sourceTable의 컬럼) */
parentKeyColumn: string;
/** 드롭다운 value로 사용할 컬럼명 */
valueColumn: string;
/** 드롭다운 label로 표시할 컬럼명 */
labelColumn: string;
/** 추가 필터 조건 (선택사항) */
additionalFilters?: Record<string, unknown>;
/** 부모 값이 없을 때 표시할 메시지 */
emptyParentMessage?: string;
/** 옵션이 없을 때 표시할 메시지 */
noOptionsMessage?: string;
/** 로딩 중 표시할 메시지 */
loadingMessage?: string;
/** 부모 값 변경 시 자동으로 값 초기화 */
clearOnParentChange?: boolean;
}
@@ -472,23 +475,23 @@ export interface ButtonTypeConfig {
export interface QuickInsertColumnMapping {
/** 저장할 테이블의 대상 컬럼명 */
targetColumn: string;
/** 값 소스 타입 */
sourceType: "component" | "leftPanel" | "fixed" | "currentUser";
// sourceType별 추가 설정
/** component: 값을 가져올 컴포넌트 ID */
sourceComponentId?: string;
/** component: 컴포넌트의 columnName (formData 접근용) */
sourceColumnName?: string;
/** leftPanel: 좌측 선택 데이터의 컬럼명 */
sourceColumn?: string;
/** fixed: 고정값 */
fixedValue?: any;
/** currentUser: 사용자 정보 필드 */
userField?: "userId" | "userName" | "companyCode" | "deptCode";
}
@@ -499,13 +502,13 @@ export interface QuickInsertColumnMapping {
export interface QuickInsertAfterAction {
/** 데이터 새로고침 (테이블리스트, 카드 디스플레이 컴포넌트) */
refreshData?: boolean;
/** 초기화할 컴포넌트 ID 목록 */
clearComponents?: string[];
/** 성공 메시지 표시 여부 */
showSuccessMessage?: boolean;
/** 커스텀 성공 메시지 */
successMessage?: string;
}
@@ -516,20 +519,20 @@ export interface QuickInsertAfterAction {
export interface QuickInsertDuplicateCheck {
/** 중복 체크 활성화 */
enabled: boolean;
/** 중복 체크할 컬럼들 */
columns: string[];
/** 중복 시 에러 메시지 */
errorMessage?: string;
}
/**
* 즉시 저장(quickInsert) 버튼 액션 설정
*
*
* 화면에서 entity 타입 선택박스로 데이터를 선택한 후,
* 버튼 클릭 시 특정 테이블에 즉시 INSERT하는 기능
*
*
* @example
* ```typescript
* const config: QuickInsertConfig = {
@@ -557,13 +560,13 @@ export interface QuickInsertDuplicateCheck {
export interface QuickInsertConfig {
/** 저장할 대상 테이블명 */
targetTable: string;
/** 컬럼 매핑 설정 */
columnMappings: QuickInsertColumnMapping[];
/** 저장 후 동작 설정 */
afterInsert?: QuickInsertAfterAction;
/** 중복 체크 설정 (선택사항) */
duplicateCheck?: QuickInsertDuplicateCheck;
}
@@ -678,15 +681,15 @@ export interface DataTableFilter {
export interface ColumnFilter {
id: string;
columnName: string; // 필터링할 컬럼명
operator:
| "equals"
| "not_equals"
| "in"
| "not_in"
| "contains"
| "starts_with"
| "ends_with"
| "is_null"
operator:
| "equals"
| "not_equals"
| "in"
| "not_in"
| "contains"
| "starts_with"
| "ends_with"
| "is_null"
| "is_not_null"
| "greater_than"
| "less_than"
@@ -836,12 +839,71 @@ export interface GroupState {
groupTitle?: string;
}
// ============================================
// 레이어 시스템 타입 정의
// ============================================
/**
* 레이어 타입
* - base: 기본 레이어 (항상 표시)
* - conditional: 조건부 레이어 (특정 조건 만족 시 표시)
* - modal: 모달 레이어 (팝업 형태)
* - drawer: 드로어 레이어 (사이드 패널 형태)
*/
export type LayerType = "base" | "conditional" | "modal" | "drawer";
/**
* 레이어 조건부 표시 설정
*/
export interface LayerCondition {
targetComponentId: string; // 트리거가 되는 컴포넌트 ID
operator: "eq" | "neq" | "in"; // 비교 연산자
value: any; // 비교할 값
}
/**
* 레이어 오버레이 설정 (모달/드로어용)
*/
export interface LayerOverlayConfig {
backdrop: boolean; // 배경 어둡게 처리 여부
closeOnBackdropClick: boolean; // 배경 클릭 시 닫기 여부
width?: string | number; // 너비
height?: string | number; // 높이
// 모달/드로어 스타일링
backgroundColor?: string; // 컨텐츠 배경색
backdropBlur?: number; // 배경 블러 (px)
// 드로어 전용
position?: "left" | "right" | "top" | "bottom"; // 드로어 위치
}
/**
* 레이어 정의
*/
export interface LayerDefinition {
id: string;
name: string;
type: LayerType;
zIndex: number;
isVisible: boolean; // 초기 표시 여부
isLocked: boolean; // 편집 잠금 여부
// 조건부 표시 로직
condition?: LayerCondition;
// 모달/드로어 전용 설정
overlayConfig?: LayerOverlayConfig;
// 해당 레이어에 속한 컴포넌트들
components: ComponentData[];
}
/**
* 레이아웃 데이터
*/
export interface LayoutData {
screenId: number;
components: ComponentData[];
components: ComponentData[]; // @deprecated - use layers instead (kept for backward compatibility)
layers?: LayerDefinition[]; // 🆕 레이어 목록
gridSettings?: GridSettings;
metadata?: LayoutMetadata;
screenResolution?: ScreenResolution;