2025-09-01 11:48:12 +09:00
|
|
|
// 화면관리 시스템 타입 정의
|
|
|
|
|
|
|
|
|
|
// 기본 컴포넌트 타입
|
|
|
|
|
export type ComponentType = "container" | "row" | "column" | "widget" | "group";
|
|
|
|
|
|
|
|
|
|
// 웹 타입 정의
|
|
|
|
|
export type WebType =
|
|
|
|
|
| "text"
|
|
|
|
|
| "number"
|
|
|
|
|
| "date"
|
|
|
|
|
| "code"
|
|
|
|
|
| "entity"
|
|
|
|
|
| "textarea"
|
|
|
|
|
| "select"
|
|
|
|
|
| "checkbox"
|
|
|
|
|
| "radio"
|
2025-09-01 14:00:31 +09:00
|
|
|
| "file"
|
|
|
|
|
| "email"
|
|
|
|
|
| "tel"
|
|
|
|
|
| "datetime"
|
|
|
|
|
| "dropdown"
|
|
|
|
|
| "text_area"
|
|
|
|
|
| "boolean"
|
|
|
|
|
| "decimal";
|
2025-09-01 11:48:12 +09:00
|
|
|
|
|
|
|
|
// 위치 정보
|
|
|
|
|
export interface Position {
|
|
|
|
|
x: number;
|
|
|
|
|
y: number;
|
2025-09-02 10:33:41 +09:00
|
|
|
z?: number; // z-index (레이어 순서)
|
2025-09-01 11:48:12 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 크기 정보
|
|
|
|
|
export interface Size {
|
|
|
|
|
width: number; // 1-12 그리드
|
|
|
|
|
height: number; // 픽셀
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-01 14:00:31 +09:00
|
|
|
// 테이블 정보
|
|
|
|
|
export interface TableInfo {
|
|
|
|
|
tableName: string;
|
|
|
|
|
tableLabel: string;
|
|
|
|
|
columns: ColumnInfo[];
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-01 11:48:12 +09:00
|
|
|
// 스타일 관련 타입
|
|
|
|
|
export interface ComponentStyle {
|
|
|
|
|
// 레이아웃
|
|
|
|
|
width?: string | number;
|
|
|
|
|
height?: string | number;
|
|
|
|
|
minWidth?: string | number;
|
|
|
|
|
minHeight?: string | number;
|
|
|
|
|
maxWidth?: string | number;
|
|
|
|
|
maxHeight?: string | number;
|
|
|
|
|
|
|
|
|
|
// 여백
|
|
|
|
|
margin?: string;
|
|
|
|
|
marginTop?: string | number;
|
|
|
|
|
marginRight?: string | number;
|
|
|
|
|
marginBottom?: string | number;
|
|
|
|
|
marginLeft?: string | number;
|
|
|
|
|
|
|
|
|
|
// 패딩
|
|
|
|
|
padding?: string;
|
|
|
|
|
paddingTop?: string | number;
|
|
|
|
|
paddingRight?: string | number;
|
|
|
|
|
paddingBottom?: string | number;
|
|
|
|
|
paddingLeft?: string | number;
|
|
|
|
|
|
|
|
|
|
// 테두리
|
|
|
|
|
border?: string;
|
|
|
|
|
borderWidth?: string | number;
|
|
|
|
|
borderStyle?: "solid" | "dashed" | "dotted" | "none";
|
|
|
|
|
borderColor?: string;
|
|
|
|
|
borderRadius?: string | number;
|
|
|
|
|
|
|
|
|
|
// 배경
|
|
|
|
|
backgroundColor?: string;
|
|
|
|
|
backgroundImage?: string;
|
|
|
|
|
backgroundSize?: "cover" | "contain" | "auto";
|
|
|
|
|
backgroundPosition?: string;
|
|
|
|
|
backgroundRepeat?: "repeat" | "no-repeat" | "repeat-x" | "repeat-y";
|
|
|
|
|
|
|
|
|
|
// 텍스트
|
|
|
|
|
color?: string;
|
|
|
|
|
fontSize?: string | number;
|
|
|
|
|
fontWeight?: "normal" | "bold" | "100" | "200" | "300" | "400" | "500" | "600" | "700" | "800" | "900";
|
|
|
|
|
fontFamily?: string;
|
|
|
|
|
textAlign?: "left" | "center" | "right" | "justify";
|
|
|
|
|
lineHeight?: string | number;
|
|
|
|
|
textDecoration?: "none" | "underline" | "line-through";
|
|
|
|
|
|
|
|
|
|
// 정렬
|
|
|
|
|
display?: "block" | "inline" | "inline-block" | "flex" | "grid" | "none";
|
|
|
|
|
flexDirection?: "row" | "row-reverse" | "column" | "column-reverse";
|
|
|
|
|
justifyContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly";
|
|
|
|
|
alignItems?: "stretch" | "flex-start" | "flex-end" | "center" | "baseline";
|
|
|
|
|
gap?: string | number;
|
|
|
|
|
|
|
|
|
|
// 위치
|
|
|
|
|
position?: "static" | "relative" | "absolute" | "fixed" | "sticky";
|
|
|
|
|
top?: string | number;
|
|
|
|
|
right?: string | number;
|
|
|
|
|
bottom?: string | number;
|
|
|
|
|
left?: string | number;
|
|
|
|
|
zIndex?: number;
|
|
|
|
|
|
|
|
|
|
// 그림자
|
|
|
|
|
boxShadow?: string;
|
|
|
|
|
|
|
|
|
|
// 기타
|
|
|
|
|
opacity?: number;
|
|
|
|
|
overflow?: "visible" | "hidden" | "scroll" | "auto";
|
|
|
|
|
cursor?: string;
|
|
|
|
|
transition?: string;
|
|
|
|
|
transform?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// BaseComponent에 스타일 속성 추가
|
|
|
|
|
export interface BaseComponent {
|
|
|
|
|
id: string;
|
|
|
|
|
type: ComponentType;
|
2025-09-02 16:18:38 +09:00
|
|
|
position: Position;
|
2025-09-01 11:48:12 +09:00
|
|
|
size: { width: number; height: number };
|
|
|
|
|
parentId?: string;
|
|
|
|
|
style?: ComponentStyle; // 스타일 속성 추가
|
2025-09-01 14:00:31 +09:00
|
|
|
tableName?: string; // 테이블명 추가
|
|
|
|
|
label?: string; // 라벨 추가
|
2025-09-01 11:48:12 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 컨테이너 컴포넌트
|
|
|
|
|
export interface ContainerComponent extends BaseComponent {
|
|
|
|
|
type: "container";
|
|
|
|
|
title?: string;
|
|
|
|
|
backgroundColor?: string;
|
|
|
|
|
border?: string;
|
|
|
|
|
borderRadius?: number;
|
|
|
|
|
shadow?: string;
|
|
|
|
|
children?: string[]; // 자식 컴포넌트 ID 목록
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 그룹 컴포넌트
|
|
|
|
|
export interface GroupComponent extends BaseComponent {
|
|
|
|
|
type: "group";
|
|
|
|
|
title?: string;
|
|
|
|
|
backgroundColor?: string;
|
|
|
|
|
border?: string;
|
|
|
|
|
borderRadius?: number;
|
|
|
|
|
shadow?: string;
|
|
|
|
|
collapsible?: boolean;
|
|
|
|
|
collapsed?: boolean;
|
|
|
|
|
children?: string[]; // 자식 컴포넌트 ID 목록
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 행 컴포넌트
|
|
|
|
|
export interface RowComponent extends BaseComponent {
|
|
|
|
|
type: "row";
|
|
|
|
|
gap?: number;
|
|
|
|
|
alignItems?: "start" | "center" | "end" | "stretch";
|
|
|
|
|
justifyContent?: "start" | "center" | "end" | "space-between" | "space-around";
|
|
|
|
|
children?: string[]; // 자식 컴포넌트 ID 목록
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 열 컴포넌트
|
|
|
|
|
export interface ColumnComponent extends BaseComponent {
|
|
|
|
|
type: "column";
|
|
|
|
|
gap?: number;
|
|
|
|
|
alignItems?: "start" | "center" | "end" | "stretch";
|
|
|
|
|
justifyContent?: "start" | "center" | "end" | "space-between" | "space-around";
|
|
|
|
|
children?: string[]; // 자식 컴포넌트 ID 목록
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 위젯 컴포넌트
|
|
|
|
|
export interface WidgetComponent extends BaseComponent {
|
|
|
|
|
type: "widget";
|
|
|
|
|
tableName: string;
|
|
|
|
|
columnName: string;
|
|
|
|
|
widgetType: WebType;
|
|
|
|
|
label: string;
|
|
|
|
|
placeholder?: string;
|
|
|
|
|
required: boolean;
|
|
|
|
|
readonly: boolean;
|
|
|
|
|
validationRules?: ValidationRule[];
|
|
|
|
|
displayProperties?: Record<string, any>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 컴포넌트 유니온 타입
|
|
|
|
|
export type ComponentData = ContainerComponent | GroupComponent | RowComponent | ColumnComponent | WidgetComponent;
|
|
|
|
|
|
|
|
|
|
// 레이아웃 데이터
|
|
|
|
|
export interface LayoutData {
|
|
|
|
|
components: ComponentData[];
|
|
|
|
|
gridSettings?: GridSettings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 그리드 설정
|
|
|
|
|
export interface GridSettings {
|
|
|
|
|
columns: number; // 기본값: 12
|
|
|
|
|
gap: number; // 기본값: 16px
|
|
|
|
|
padding: number; // 기본값: 16px
|
2025-09-02 11:16:40 +09:00
|
|
|
snapToGrid?: boolean; // 격자에 맞춤 여부 (기본값: true)
|
2025-09-02 16:18:38 +09:00
|
|
|
showGrid?: boolean; // 격자 표시 여부 (기본값: true)
|
|
|
|
|
gridColor?: string; // 격자 색상 (기본값: #d1d5db)
|
|
|
|
|
gridOpacity?: number; // 격자 투명도 (기본값: 0.5)
|
2025-09-01 11:48:12 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 유효성 검증 규칙
|
|
|
|
|
export interface ValidationRule {
|
|
|
|
|
type: "required" | "minLength" | "maxLength" | "pattern" | "min" | "max" | "email" | "url";
|
|
|
|
|
value?: any;
|
|
|
|
|
message: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 화면 정의
|
|
|
|
|
export interface ScreenDefinition {
|
|
|
|
|
screenId: number;
|
|
|
|
|
screenName: string;
|
|
|
|
|
screenCode: string;
|
|
|
|
|
tableName: string;
|
|
|
|
|
companyCode: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
isActive: string;
|
|
|
|
|
createdDate: Date;
|
|
|
|
|
updatedDate: Date;
|
|
|
|
|
createdBy?: string;
|
|
|
|
|
updatedBy?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 화면 생성 요청
|
|
|
|
|
export interface CreateScreenRequest {
|
|
|
|
|
screenName: string;
|
|
|
|
|
screenCode: string;
|
|
|
|
|
tableName: string;
|
|
|
|
|
companyCode: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
createdBy?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 화면 수정 요청
|
|
|
|
|
export interface UpdateScreenRequest {
|
|
|
|
|
screenName?: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
updatedBy?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 레이아웃 저장 요청
|
|
|
|
|
export interface SaveLayoutRequest {
|
|
|
|
|
components: ComponentData[];
|
|
|
|
|
gridSettings?: GridSettings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 화면 템플릿
|
|
|
|
|
export interface ScreenTemplate {
|
|
|
|
|
templateId: number;
|
|
|
|
|
templateName: string;
|
|
|
|
|
templateType: string;
|
|
|
|
|
companyCode: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
layoutData?: LayoutData;
|
|
|
|
|
isPublic: boolean;
|
|
|
|
|
createdBy?: string;
|
|
|
|
|
createdDate: Date;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 메뉴 할당 요청
|
|
|
|
|
export interface MenuAssignmentRequest {
|
|
|
|
|
menuObjid: number;
|
|
|
|
|
companyCode: string;
|
|
|
|
|
displayOrder?: number;
|
|
|
|
|
createdBy?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 드래그 상태
|
|
|
|
|
export interface DragState {
|
|
|
|
|
isDragging: boolean;
|
|
|
|
|
draggedItem: ComponentData | null;
|
|
|
|
|
draggedComponent?: ComponentData | null; // 컴포넌트 재배치용
|
|
|
|
|
dragSource: "toolbox" | "canvas";
|
|
|
|
|
dropTarget: string | null;
|
|
|
|
|
dropZone?: DropZone;
|
|
|
|
|
dragOffset?: { x: number; y: number }; // 드래그 오프셋
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 드롭 영역
|
|
|
|
|
export interface DropZone {
|
|
|
|
|
id: string;
|
|
|
|
|
accepts: ComponentType[];
|
|
|
|
|
position: Position;
|
|
|
|
|
size: Size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 그룹화 상태
|
|
|
|
|
export interface GroupState {
|
|
|
|
|
isGrouping: boolean;
|
|
|
|
|
selectedComponents: string[];
|
2025-09-02 16:18:38 +09:00
|
|
|
groupTarget?: string | null;
|
|
|
|
|
groupMode?: "create" | "add" | "remove" | "ungroup";
|
2025-09-01 15:22:47 +09:00
|
|
|
groupTitle?: string;
|
|
|
|
|
groupStyle?: ComponentStyle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 그룹화 작업 타입
|
|
|
|
|
export interface GroupingAction {
|
|
|
|
|
type: "create" | "add" | "remove" | "ungroup";
|
|
|
|
|
componentIds: string[];
|
|
|
|
|
groupId?: string;
|
|
|
|
|
groupTitle?: string;
|
|
|
|
|
groupStyle?: ComponentStyle;
|
2025-09-01 11:48:12 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 컬럼 정보 (테이블 타입관리 연계용)
|
|
|
|
|
export interface ColumnInfo {
|
|
|
|
|
tableName: string;
|
|
|
|
|
columnName: string;
|
|
|
|
|
columnLabel?: string;
|
|
|
|
|
dataType: string;
|
|
|
|
|
webType?: WebType;
|
2025-09-02 16:18:38 +09:00
|
|
|
widgetType?: WebType; // 프론트엔드에서 사용하는 필드 (webType과 동일)
|
2025-09-01 11:48:12 +09:00
|
|
|
isNullable: string;
|
2025-09-02 16:18:38 +09:00
|
|
|
required?: boolean; // isNullable에서 변환된 필드
|
2025-09-01 11:48:12 +09:00
|
|
|
columnDefault?: string;
|
|
|
|
|
characterMaximumLength?: number;
|
|
|
|
|
numericPrecision?: number;
|
|
|
|
|
numericScale?: number;
|
|
|
|
|
detailSettings?: string; // JSON 문자열
|
|
|
|
|
codeCategory?: string;
|
|
|
|
|
referenceTable?: string;
|
|
|
|
|
referenceColumn?: string;
|
|
|
|
|
isVisible?: boolean;
|
|
|
|
|
displayOrder?: number;
|
|
|
|
|
description?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 웹 타입 설정
|
|
|
|
|
export interface ColumnWebTypeSetting {
|
|
|
|
|
tableName: string;
|
|
|
|
|
columnName: string;
|
|
|
|
|
webType: WebType;
|
|
|
|
|
columnLabel?: string;
|
|
|
|
|
detailSettings?: Record<string, any>;
|
|
|
|
|
codeCategory?: string;
|
|
|
|
|
referenceTable?: string;
|
|
|
|
|
referenceColumn?: string;
|
|
|
|
|
isVisible?: boolean;
|
|
|
|
|
displayOrder?: number;
|
|
|
|
|
description?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 위젯 데이터
|
|
|
|
|
export interface WidgetData {
|
|
|
|
|
id: string;
|
|
|
|
|
tableName: string;
|
|
|
|
|
columnName: string;
|
|
|
|
|
type: WebType;
|
|
|
|
|
label: string;
|
|
|
|
|
required: boolean;
|
|
|
|
|
readonly: boolean;
|
|
|
|
|
[key: string]: any; // 추가 속성들
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// API 응답 타입
|
|
|
|
|
export interface ApiResponse<T> {
|
|
|
|
|
success: boolean;
|
|
|
|
|
data?: T;
|
|
|
|
|
message?: string;
|
|
|
|
|
errorCode?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 페이지네이션 응답
|
|
|
|
|
export interface PaginatedResponse<T> {
|
|
|
|
|
data: T[];
|
|
|
|
|
total: number;
|
|
|
|
|
page: number;
|
|
|
|
|
size: number;
|
|
|
|
|
totalPages: number;
|
|
|
|
|
}
|