feat: 품목 관리 및 마스터 데이터 관리 시스템 구현
주요 기능: - 품목 CRUD 기능 (생성, 조회, 수정) - 품목 마스터 데이터 관리 시스템 - BOM(Bill of Materials) 관리 기능 - 도면 캔버스 기능 - 품목 속성 및 카테고리 관리 - 스크린 인쇄 생산 관리 페이지 기술 개선: - localStorage SSR 호환성 수정 (9개 useState 초기화) - Shadcn UI 컴포넌트 추가 (table, tabs, alert, drawer 등) - DataContext 및 DeveloperModeContext 추가 - API 라우트 구현 (items, master-data) - 타입 정의 및 유틸리티 함수 추가 빌드 테스트: ✅ 성공 (3.1초) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
352
src/types/item.ts
Normal file
352
src/types/item.ts
Normal file
@@ -0,0 +1,352 @@
|
||||
/**
|
||||
* 품목 관리 타입 정의
|
||||
*
|
||||
* React 프로젝트에서 마이그레이션
|
||||
* Source: sma-react-v2.0/src/components/contexts/DataContext.tsx
|
||||
*/
|
||||
|
||||
// ===== 기본 타입 =====
|
||||
|
||||
/**
|
||||
* 품목 유형
|
||||
* - FG: Finished Goods (완제품)
|
||||
* - PT: Parts (부품)
|
||||
* - SM: Sub-Materials (부자재)
|
||||
* - RM: Raw Materials (원자재)
|
||||
* - CS: Consumables (소모품)
|
||||
*/
|
||||
export type ItemType = 'FG' | 'PT' | 'SM' | 'RM' | 'CS';
|
||||
|
||||
/**
|
||||
* 제품 카테고리
|
||||
*/
|
||||
export type ProductCategory = 'SCREEN' | 'STEEL';
|
||||
|
||||
/**
|
||||
* 부품 유형
|
||||
* - ASSEMBLY: 조립 부품
|
||||
* - BENDING: 절곡 부품
|
||||
* - PURCHASED: 구매 부품
|
||||
*/
|
||||
export type PartType = 'ASSEMBLY' | 'BENDING' | 'PURCHASED';
|
||||
|
||||
/**
|
||||
* 부품 용도
|
||||
*/
|
||||
export type PartUsage =
|
||||
| 'GUIDE_RAIL' // 가이드레일
|
||||
| 'BOTTOM_FINISH' // 하단마감재
|
||||
| 'CASE' // 케이스
|
||||
| 'DOOR' // 도어
|
||||
| 'BRACKET' // 브라켓
|
||||
| 'GENERAL'; // 일반
|
||||
|
||||
// ===== 절곡품 전개도 =====
|
||||
|
||||
/**
|
||||
* 절곡품 전개도 상세 데이터
|
||||
*/
|
||||
export interface BendingDetail {
|
||||
id: string;
|
||||
no: number; // 번호
|
||||
input: number; // 입력값
|
||||
elongation: number; // 연신율 (기본값 -1)
|
||||
calculated: number; // 연신율 계산 후 값
|
||||
sum: number; // 합계
|
||||
shaded: boolean; // 음영 여부
|
||||
aAngle?: number; // A각
|
||||
}
|
||||
|
||||
// ===== BOM (자재명세서) =====
|
||||
|
||||
/**
|
||||
* 부품구성표 (Bill of Materials)
|
||||
* 제품의 하위 구성 품목 정보
|
||||
*/
|
||||
export interface BOMLine {
|
||||
id: string;
|
||||
childItemCode: string; // 하위 품목 코드
|
||||
childItemName: string; // 하위 품목명
|
||||
specification?: string; // 규격
|
||||
material?: string; // 재질
|
||||
quantity: number; // 기준 수량
|
||||
unit: string; // 단위
|
||||
unitPrice?: number; // 단가
|
||||
quantityFormula?: string; // 수량 계산식 (예: "W * 2", "H + 100")
|
||||
note?: string; // 비고
|
||||
width?: number; // 폭 (절곡품)
|
||||
|
||||
// 절곡품 관련 (하위 절곡 부품용)
|
||||
isBending?: boolean; // 절곡품 여부
|
||||
bendingDiagram?: string; // 전개도 이미지 URL
|
||||
bendingDetails?: BendingDetail[]; // 전개도 상세 데이터
|
||||
}
|
||||
|
||||
// ===== 품목 수정 이력 =====
|
||||
|
||||
/**
|
||||
* 품목 수정 이력
|
||||
*/
|
||||
export interface ItemRevision {
|
||||
revisionNumber: number; // 수정 차수 (1차, 2차, 3차...)
|
||||
revisionDate: string; // 수정일
|
||||
revisionBy: string; // 수정자
|
||||
revisionReason?: string; // 수정 사유
|
||||
previousData: any; // 이전 버전의 전체 데이터
|
||||
}
|
||||
|
||||
// ===== 품목 마스터 (메인) =====
|
||||
|
||||
/**
|
||||
* 품목 마스터 데이터
|
||||
* 모든 품목 유형(FG/PT/SM/RM/CS)을 포괄하는 통합 인터페이스
|
||||
*/
|
||||
export interface ItemMaster {
|
||||
// === 공통 필드 (모든 품목 유형) ===
|
||||
id: string;
|
||||
itemCode: string; // 품목 코드 (예: "KD-FG-001")
|
||||
itemName: string; // 품목명
|
||||
itemType: ItemType; // 품목 유형
|
||||
unit: string; // 단위 (EA, SET, KG, M 등)
|
||||
specification?: string; // 규격
|
||||
isActive?: boolean; // 활성/비활성
|
||||
|
||||
// === 분류 ===
|
||||
category1?: string; // 대분류
|
||||
category2?: string; // 중분류
|
||||
category3?: string; // 소분류
|
||||
|
||||
// === 가격 정보 ===
|
||||
purchasePrice?: number; // 구매 단가
|
||||
salesPrice?: number; // 판매 단가
|
||||
marginRate?: number; // 마진율
|
||||
processingCost?: number; // 가공비
|
||||
laborCost?: number; // 노무비
|
||||
installCost?: number; // 설치비
|
||||
|
||||
// === BOM (자재명세서) ===
|
||||
bom?: BOMLine[]; // 하위 품목 구성
|
||||
bomCategories?: string[]; // BOM 카테고리
|
||||
|
||||
// === 제품(FG) 전용 필드 ===
|
||||
productName?: string; // 상품명 (고객용)
|
||||
productCategory?: ProductCategory; // 제품 카테고리
|
||||
lotAbbreviation?: string; // 로트 약자 (예: "KD")
|
||||
note?: string; // 비고
|
||||
|
||||
// === 부품(PT) 전용 필드 ===
|
||||
partType?: PartType; // 부품 유형
|
||||
partUsage?: PartUsage; // 부품 용도
|
||||
|
||||
// 조립 부품 관련
|
||||
installationType?: string; // 설치 유형 (벽면형/측면형)
|
||||
assemblyType?: string; // 종류 (M/T/C/D/S/U)
|
||||
sideSpecWidth?: string; // 측면 규격 가로 (mm)
|
||||
sideSpecHeight?: string; // 측면 규격 세로 (mm)
|
||||
assemblyLength?: string; // 길이 (2438/3000/3500/4000/4300)
|
||||
|
||||
// 가이드레일 관련
|
||||
guideRailModelType?: string; // 가이드레일 모델 유형
|
||||
guideRailModel?: string; // 가이드레일 모델
|
||||
|
||||
// 절곡품 관련
|
||||
bendingDiagram?: string; // 전개도 이미지 URL
|
||||
bendingDetails?: BendingDetail[]; // 전개도 상세 데이터
|
||||
material?: string; // 재질 (EGI 1.55T, SUS 1.2T)
|
||||
length?: string; // 길이/목함 (mm)
|
||||
bendingLength?: string; // 절곡품 길이 규격
|
||||
|
||||
// 구매 부품 관련
|
||||
electricOpenerPower?: string; // 전동개폐기 전원 (220V/380V)
|
||||
electricOpenerCapacity?: string; // 전동개폐기 용량 (150/300/400/500/600/800/1000 KG)
|
||||
motorVoltage?: string; // 모터 전압 (220V/380V)
|
||||
motorCapacity?: string; // 모터 용량 (kg)
|
||||
chainSpec?: string; // 체인 규격
|
||||
|
||||
// === 인정 정보 (제품/부품) ===
|
||||
certificationNumber?: string; // 인정번호
|
||||
certificationStartDate?: string; // 인정 유효기간 시작일
|
||||
certificationEndDate?: string; // 인정 유효기간 종료일
|
||||
specificationFile?: string; // 시방서 파일 URL
|
||||
specificationFileName?: string; // 시방서 파일명
|
||||
certificationFile?: string; // 인정서 파일 URL
|
||||
certificationFileName?: string; // 인정서 파일명
|
||||
|
||||
// === 메타데이터 ===
|
||||
safetyStock?: number; // 안전재고
|
||||
leadTime?: number; // 리드타임
|
||||
isVariableSize?: boolean; // 가변 크기 여부
|
||||
|
||||
// 버전 관리
|
||||
currentRevision: number; // 현재 차수 (0 = 최초, 1 = 1차 수정...)
|
||||
revisions?: ItemRevision[]; // 수정 이력
|
||||
isFinal: boolean; // 최종 확정 여부
|
||||
finalizedDate?: string; // 최종 확정일
|
||||
finalizedBy?: string; // 최종 확정자
|
||||
|
||||
createdAt: string;
|
||||
updatedAt?: string;
|
||||
}
|
||||
|
||||
// ===== API 응답 타입 =====
|
||||
|
||||
/**
|
||||
* Laravel API 응답 기본 구조
|
||||
*/
|
||||
export interface ApiResponse<T> {
|
||||
success: boolean;
|
||||
data: T;
|
||||
message?: string;
|
||||
errors?: Record<string, string[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 페이지네이션 응답
|
||||
*/
|
||||
export interface PaginatedResponse<T> {
|
||||
data: T[];
|
||||
current_page: number;
|
||||
last_page: number;
|
||||
per_page: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 품목 목록 조회 파라미터
|
||||
*/
|
||||
export interface FetchItemsParams {
|
||||
itemType?: ItemType;
|
||||
search?: string;
|
||||
category1?: string;
|
||||
category2?: string;
|
||||
category3?: string;
|
||||
isActive?: boolean;
|
||||
page?: number;
|
||||
per_page?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 품목 생성/수정 데이터
|
||||
*/
|
||||
export type CreateItemData = Omit<ItemMaster, 'id' | 'createdAt' | 'updatedAt' | 'currentRevision' | 'revisions' | 'isFinal'>;
|
||||
export type UpdateItemData = Partial<CreateItemData>;
|
||||
|
||||
// ===== 동적 템플릿 시스템 타입 (선택적) =====
|
||||
|
||||
/**
|
||||
* 필드 표시 조건
|
||||
*/
|
||||
export interface FieldDisplayCondition {
|
||||
dependsOn: string; // 의존하는 필드 키
|
||||
showWhen: string | string[]; // 표시 조건 값
|
||||
hideWhen?: string | string[]; // 숨김 조건 값
|
||||
}
|
||||
|
||||
/**
|
||||
* 필드 속성
|
||||
*/
|
||||
export interface ItemFieldProperty {
|
||||
id?: string;
|
||||
key?: string;
|
||||
label?: string;
|
||||
type?: 'textbox' | 'dropdown' | 'checkbox' | 'number' | 'date' | 'textarea';
|
||||
inputType: 'textbox' | 'dropdown' | 'checkbox' | 'number' | 'date' | 'textarea' | 'section';
|
||||
required: boolean;
|
||||
row: number;
|
||||
col: number;
|
||||
options?: string[];
|
||||
defaultValue?: string;
|
||||
placeholder?: string;
|
||||
multiColumn?: boolean;
|
||||
columnCount?: number;
|
||||
columnNames?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 필드 정의
|
||||
*/
|
||||
export interface ItemField {
|
||||
id: string;
|
||||
name: string; // 항목명
|
||||
fieldKey: string; // 필드 키
|
||||
property: ItemFieldProperty; // 속성
|
||||
displayCondition?: FieldDisplayCondition; // 조건부 표시
|
||||
}
|
||||
|
||||
/**
|
||||
* 섹션 정의
|
||||
*/
|
||||
export interface ItemSection {
|
||||
id: string;
|
||||
title: string; // 섹션 제목
|
||||
description?: string; // 설명
|
||||
category?: string[]; // 카테고리 조건
|
||||
fields: ItemField[]; // 섹션에 포함된 항목들
|
||||
type?: 'fields' | 'bom'; // 섹션 타입
|
||||
order: number; // 섹션 순서
|
||||
isCollapsible: boolean; // 접기/펼치기 가능 여부
|
||||
isCollapsed: boolean; // 기본 접힘 상태
|
||||
}
|
||||
|
||||
/**
|
||||
* 페이지 템플릿 정의
|
||||
*/
|
||||
export interface ItemPage {
|
||||
id: string;
|
||||
pageName: string; // 페이지명
|
||||
itemType: ItemType; // 품목 유형
|
||||
sections: ItemSection[]; // 페이지 내 섹션들
|
||||
isActive: boolean; // 사용 여부
|
||||
absolutePath?: string; // 절대경로
|
||||
createdAt: string;
|
||||
updatedAt?: string;
|
||||
}
|
||||
|
||||
// ===== 유틸리티 타입 =====
|
||||
|
||||
/**
|
||||
* 품목 코드 체계
|
||||
* 형식: {업체코드}-{품목유형}-{일련번호}
|
||||
* 예: KD-FG-001, KD-PT-001
|
||||
*/
|
||||
export type ItemCodeFormat = `${string}-${ItemType}-${string}`;
|
||||
|
||||
/**
|
||||
* 품목 유형 라벨 맵
|
||||
*/
|
||||
export const ITEM_TYPE_LABELS: Record<ItemType, string> = {
|
||||
FG: '제품',
|
||||
PT: '부품',
|
||||
SM: '부자재',
|
||||
RM: '원자재',
|
||||
CS: '소모품',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* 제품 카테고리 라벨
|
||||
*/
|
||||
export const PRODUCT_CATEGORY_LABELS: Record<ProductCategory, string> = {
|
||||
SCREEN: '스크린',
|
||||
STEEL: '철재',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* 부품 유형 라벨
|
||||
*/
|
||||
export const PART_TYPE_LABELS: Record<PartType, string> = {
|
||||
ASSEMBLY: '조립 부품',
|
||||
BENDING: '절곡 부품',
|
||||
PURCHASED: '구매 부품',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* 부품 용도 라벨
|
||||
*/
|
||||
export const PART_USAGE_LABELS: Record<PartUsage, string> = {
|
||||
GUIDE_RAIL: '가이드레일',
|
||||
BOTTOM_FINISH: '하단마감재',
|
||||
CASE: '케이스',
|
||||
DOOR: '도어',
|
||||
BRACKET: '브라켓',
|
||||
GENERAL: '일반',
|
||||
} as const;
|
||||
283
src/types/master-data.ts
Normal file
283
src/types/master-data.ts
Normal file
@@ -0,0 +1,283 @@
|
||||
/**
|
||||
* 품목기준관리 타입 정의
|
||||
*
|
||||
* 동적 페이지 구성, 버전 관리, 멀티테넌시 지원
|
||||
*/
|
||||
|
||||
import type { ItemType } from './item';
|
||||
|
||||
// ===== 페이지 타입 =====
|
||||
|
||||
/**
|
||||
* 페이지 유형
|
||||
* - item-master: 품목기준정보
|
||||
* - quotation: 견적
|
||||
* - sales-order: 수주
|
||||
* - formula: 계산식
|
||||
* - pricing: 단가
|
||||
*/
|
||||
export type PageType = 'item-master' | 'quotation' | 'sales-order' | 'formula' | 'pricing';
|
||||
|
||||
/**
|
||||
* 필드 입력 타입
|
||||
*/
|
||||
export type FieldInputType =
|
||||
| 'textbox'
|
||||
| 'dropdown'
|
||||
| 'checkbox'
|
||||
| 'number'
|
||||
| 'date'
|
||||
| 'textarea'
|
||||
| 'file'
|
||||
| 'multi-column';
|
||||
|
||||
/**
|
||||
* 섹션 타입
|
||||
*/
|
||||
export type SectionType = 'fields' | 'bom' | 'table';
|
||||
|
||||
// ===== 필드 설정 =====
|
||||
|
||||
/**
|
||||
* 필드 표시 조건
|
||||
*/
|
||||
export interface FieldDisplayCondition {
|
||||
dependsOn: string; // 의존하는 필드 키
|
||||
showWhen?: string | string[]; // 표시 조건 값
|
||||
hideWhen?: string | string[]; // 숨김 조건 값
|
||||
}
|
||||
|
||||
/**
|
||||
* 필드 유효성 검사 규칙
|
||||
*/
|
||||
export interface FieldValidationRule {
|
||||
type: 'required' | 'min' | 'max' | 'pattern' | 'custom';
|
||||
value?: any;
|
||||
message: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 필드 속성
|
||||
*/
|
||||
export interface FieldProperty {
|
||||
inputType: FieldInputType;
|
||||
required: boolean;
|
||||
row: number; // 그리드 행 번호
|
||||
col: number; // 그리드 열 번호
|
||||
options?: string[]; // 드롭다운 옵션
|
||||
defaultValue?: any;
|
||||
placeholder?: string;
|
||||
|
||||
// 멀티컬럼 필드 관련
|
||||
multiColumn?: boolean;
|
||||
columnCount?: number;
|
||||
columnNames?: string[];
|
||||
|
||||
// 유효성 검사
|
||||
validation?: FieldValidationRule[];
|
||||
|
||||
// 표시 조건
|
||||
displayCondition?: FieldDisplayCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 필드 정의
|
||||
*/
|
||||
export interface FieldConfig {
|
||||
id: string;
|
||||
name: string; // 필드 라벨
|
||||
fieldKey: string; // 데이터 키
|
||||
property: FieldProperty;
|
||||
helpText?: string; // 도움말 텍스트
|
||||
}
|
||||
|
||||
// ===== 섹션 설정 =====
|
||||
|
||||
/**
|
||||
* 섹션 정의
|
||||
*/
|
||||
export interface SectionConfig {
|
||||
id: string;
|
||||
title: string; // 섹션 제목
|
||||
description?: string;
|
||||
type: SectionType;
|
||||
fields: FieldConfig[];
|
||||
order: number; // 섹션 순서
|
||||
isCollapsible: boolean; // 접기/펼치기 가능 여부
|
||||
isCollapsed: boolean; // 기본 접힘 상태
|
||||
|
||||
// 조건부 표시
|
||||
category?: string[]; // 특정 카테고리에서만 표시
|
||||
}
|
||||
|
||||
// ===== 페이지 설정 =====
|
||||
|
||||
/**
|
||||
* 페이지 구성 정보
|
||||
*/
|
||||
export interface PageConfig {
|
||||
id: string;
|
||||
pageName: string; // 페이지명
|
||||
pageType: PageType; // 페이지 유형
|
||||
itemType?: ItemType; // 연결된 품목 유형 (optional)
|
||||
sections: SectionConfig[]; // 섹션 목록
|
||||
isActive: boolean; // 사용 여부
|
||||
|
||||
// 버전 관리
|
||||
version: number; // 현재 버전
|
||||
isFinal: boolean; // 최종 확정 여부
|
||||
|
||||
// 멀티테넌시
|
||||
tenantId: string; // 테넌트 ID
|
||||
|
||||
// 메타데이터
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
createdBy: string;
|
||||
updatedBy?: string;
|
||||
}
|
||||
|
||||
// ===== 버전 관리 =====
|
||||
|
||||
/**
|
||||
* 페이지 구성 변경 이력
|
||||
*/
|
||||
export interface PageConfigRevision {
|
||||
id: string;
|
||||
pageConfigId: string;
|
||||
version: number; // 버전 번호
|
||||
previousVersion: number; // 이전 버전
|
||||
changes: PageConfigChange[]; // 변경 내역
|
||||
snapshot: PageConfig; // 전체 스냅샷
|
||||
|
||||
// 변경 정보
|
||||
changedAt: string;
|
||||
changedBy: string;
|
||||
changeReason?: string;
|
||||
|
||||
// 승인 정보
|
||||
isApproved: boolean;
|
||||
approvedAt?: string;
|
||||
approvedBy?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 페이지 구성 변경 상세
|
||||
*/
|
||||
export interface PageConfigChange {
|
||||
type: 'field_added' | 'field_removed' | 'field_modified' | 'section_added' | 'section_removed' | 'section_modified';
|
||||
targetId: string; // 변경된 필드/섹션 ID
|
||||
fieldName?: string; // 변경된 항목명
|
||||
oldValue?: any;
|
||||
newValue?: any;
|
||||
description: string;
|
||||
}
|
||||
|
||||
// ===== 데이터 입력 =====
|
||||
|
||||
/**
|
||||
* 동적 폼 데이터
|
||||
*/
|
||||
export interface DynamicFormData {
|
||||
id?: string;
|
||||
pageConfigId: string;
|
||||
pageType: PageType;
|
||||
tenantId: string;
|
||||
|
||||
// 동적 필드 데이터 (key-value)
|
||||
fieldData: Record<string, any>;
|
||||
|
||||
// 버전 관리
|
||||
version: number;
|
||||
isFinal: boolean;
|
||||
|
||||
// 메타데이터
|
||||
createdAt?: string;
|
||||
updatedAt?: string;
|
||||
createdBy?: string;
|
||||
updatedBy?: string;
|
||||
}
|
||||
|
||||
// ===== API 응답 =====
|
||||
|
||||
/**
|
||||
* API 응답 기본 구조
|
||||
*/
|
||||
export interface MasterDataApiResponse<T> {
|
||||
success: boolean;
|
||||
data: T;
|
||||
message?: string;
|
||||
errors?: Record<string, string[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 페이지네이션 응답
|
||||
*/
|
||||
export interface MasterDataPaginatedResponse<T> {
|
||||
data: T[];
|
||||
current_page: number;
|
||||
last_page: number;
|
||||
per_page: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 페이지 구성 조회 파라미터
|
||||
*/
|
||||
export interface FetchPageConfigParams {
|
||||
pageType?: PageType;
|
||||
itemType?: ItemType;
|
||||
isActive?: boolean;
|
||||
version?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 버전 비교 결과
|
||||
*/
|
||||
export interface VersionComparisonResult {
|
||||
version1: number;
|
||||
version2: number;
|
||||
changes: PageConfigChange[];
|
||||
addedFields: FieldConfig[];
|
||||
removedFields: FieldConfig[];
|
||||
modifiedFields: Array<{
|
||||
field: FieldConfig;
|
||||
changes: Record<string, { old: any; new: any }>;
|
||||
}>;
|
||||
}
|
||||
|
||||
// ===== 유틸리티 타입 =====
|
||||
|
||||
/**
|
||||
* 페이지 타입 라벨
|
||||
*/
|
||||
export const PAGE_TYPE_LABELS: Record<PageType, string> = {
|
||||
'item-master': '품목기준정보',
|
||||
'quotation': '견적',
|
||||
'sales-order': '수주',
|
||||
'formula': '계산식',
|
||||
'pricing': '단가',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* 섹션 타입 라벨
|
||||
*/
|
||||
export const SECTION_TYPE_LABELS: Record<SectionType, string> = {
|
||||
'fields': '입력 필드',
|
||||
'bom': '부품구성표',
|
||||
'table': '테이블',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* 필드 입력 타입 라벨
|
||||
*/
|
||||
export const FIELD_INPUT_TYPE_LABELS: Record<FieldInputType, string> = {
|
||||
'textbox': '텍스트 입력',
|
||||
'dropdown': '드롭다운',
|
||||
'checkbox': '체크박스',
|
||||
'number': '숫자 입력',
|
||||
'date': '날짜',
|
||||
'textarea': '텍스트 영역',
|
||||
'file': '파일',
|
||||
'multi-column': '다중 컬럼',
|
||||
} as const;
|
||||
Reference in New Issue
Block a user