[feat]: Item Master 데이터 관리 기능 구현 및 타입 에러 수정
- ItemMasterDataManagement 컴포넌트 구조화 (tabs, dialogs, components 분리) - HierarchyTab 타입 에러 수정 (BOMItem section_id, updated_at 추가) - API 클라이언트 구현 (item-master.ts, 13개 엔드포인트) - ItemMasterContext 구현 (상태 관리 및 데이터 흐름) - 백엔드 요구사항 문서 작성 (CORS 설정, API 스펙 등) - SSR 호환성 수정 (navigator API typeof window 체크) - 미사용 변수 ESLint 에러 해결 - Context 리팩토링 (AuthContext, RootProvider 추가) - API 유틸리티 추가 (error-handler, logger, transformers) 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
412
src/types/item-master-api.ts
Normal file
412
src/types/item-master-api.ts
Normal file
@@ -0,0 +1,412 @@
|
||||
// 품목기준관리 API 타입 정의
|
||||
// API 응답 기준 snake_case 사용
|
||||
|
||||
// ============================================
|
||||
// 공통 타입
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 표준 API 응답 래퍼
|
||||
*/
|
||||
export interface ApiResponse<T> {
|
||||
success: boolean;
|
||||
message: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 페이지네이션 메타데이터
|
||||
*/
|
||||
export interface PaginationMeta {
|
||||
current_page: number;
|
||||
per_page: number;
|
||||
total: number;
|
||||
last_page: number;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 초기화 API
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 초기화 API 응답 - 화면 진입 시 전체 데이터 로드
|
||||
* GET /v1/item-master/init
|
||||
*/
|
||||
export interface InitResponse {
|
||||
pages: ItemPageResponse[];
|
||||
sectionTemplates: SectionTemplateResponse[];
|
||||
masterFields: MasterFieldResponse[];
|
||||
customTabs: CustomTabResponse[];
|
||||
tabColumns: Record<number, TabColumnResponse[]>; // tab_id를 key로 사용
|
||||
unitOptions: UnitOptionResponse[];
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 페이지 관리
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 페이지 생성/수정 요청
|
||||
* POST /v1/item-master/pages
|
||||
* PUT /v1/item-master/pages/{id}
|
||||
*/
|
||||
export interface ItemPageRequest {
|
||||
page_name: string;
|
||||
item_type: 'FG' | 'PT' | 'SM' | 'RM' | 'CS';
|
||||
absolute_path?: string;
|
||||
is_active?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 페이지 응답
|
||||
*/
|
||||
export interface ItemPageResponse {
|
||||
id: number;
|
||||
tenant_id: number;
|
||||
page_name: string;
|
||||
item_type: string;
|
||||
absolute_path: string | null;
|
||||
is_active: boolean;
|
||||
created_by: number | null;
|
||||
updated_by: number | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
sections?: ItemSectionResponse[]; // Nested 조회 시 포함
|
||||
}
|
||||
|
||||
/**
|
||||
* 페이지 순서 변경 요청
|
||||
* PUT /v1/item-master/pages/reorder (향후 구현 가능성)
|
||||
*/
|
||||
export interface PageReorderRequest {
|
||||
page_orders: Array<{
|
||||
id: number;
|
||||
order_no: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 섹션 관리
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 섹션 생성/수정 요청
|
||||
* POST /v1/item-master/pages/{pageId}/sections
|
||||
* PUT /v1/item-master/sections/{id}
|
||||
*/
|
||||
export interface ItemSectionRequest {
|
||||
title: string;
|
||||
type: 'fields' | 'bom';
|
||||
}
|
||||
|
||||
/**
|
||||
* 섹션 응답
|
||||
*/
|
||||
export interface ItemSectionResponse {
|
||||
id: number;
|
||||
tenant_id: number;
|
||||
page_id: number;
|
||||
title: string;
|
||||
type: 'fields' | 'bom';
|
||||
order_no: number;
|
||||
created_by: number | null;
|
||||
updated_by: number | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
fields?: ItemFieldResponse[]; // Nested 조회 시 포함
|
||||
bomItems?: BomItemResponse[]; // Nested 조회 시 포함
|
||||
}
|
||||
|
||||
/**
|
||||
* 섹션 순서 변경 요청
|
||||
* PUT /v1/item-master/pages/{pageId}/sections/reorder
|
||||
*/
|
||||
export interface SectionReorderRequest {
|
||||
section_orders: Array<{
|
||||
id: number;
|
||||
order_no: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 필드 관리
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 필드 생성/수정 요청
|
||||
* POST /v1/item-master/sections/{sectionId}/fields
|
||||
* PUT /v1/item-master/fields/{id}
|
||||
*/
|
||||
export interface ItemFieldRequest {
|
||||
field_name: string;
|
||||
field_type: 'textbox' | 'number' | 'dropdown' | 'checkbox' | 'date' | 'textarea';
|
||||
is_required?: boolean;
|
||||
placeholder?: string;
|
||||
default_value?: string;
|
||||
display_condition?: Record<string, any>; // {"field_id": "1", "operator": "equals", "value": "true"}
|
||||
validation_rules?: Record<string, any>; // {"min": 0, "max": 100, "pattern": "regex"}
|
||||
options?: Array<{ label: string; value: string }>; // dropdown 옵션
|
||||
properties?: Record<string, any>; // {"unit": "mm", "precision": 2, "format": "YYYY-MM-DD"}
|
||||
}
|
||||
|
||||
/**
|
||||
* 필드 응답
|
||||
*/
|
||||
export interface ItemFieldResponse {
|
||||
id: number;
|
||||
tenant_id: number;
|
||||
section_id: number;
|
||||
field_name: string;
|
||||
field_type: 'textbox' | 'number' | 'dropdown' | 'checkbox' | 'date' | 'textarea';
|
||||
order_no: number;
|
||||
is_required: boolean;
|
||||
placeholder: string | null;
|
||||
default_value: string | null;
|
||||
display_condition: Record<string, any> | null;
|
||||
validation_rules: Record<string, any> | null;
|
||||
options: Array<{ label: string; value: string }> | null;
|
||||
properties: Record<string, any> | null;
|
||||
created_by: number | null;
|
||||
updated_by: number | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 필드 순서 변경 요청
|
||||
* PUT /v1/item-master/sections/{sectionId}/fields/reorder
|
||||
*/
|
||||
export interface FieldReorderRequest {
|
||||
field_orders: Array<{
|
||||
id: number;
|
||||
order_no: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// BOM 관리
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* BOM 항목 생성/수정 요청
|
||||
* POST /v1/item-master/sections/{sectionId}/bom-items
|
||||
* PUT /v1/item-master/bom-items/{id}
|
||||
*/
|
||||
export interface BomItemRequest {
|
||||
item_code?: string;
|
||||
item_name: string;
|
||||
quantity: number;
|
||||
unit?: string;
|
||||
unit_price?: number;
|
||||
total_price?: number;
|
||||
spec?: string;
|
||||
note?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* BOM 항목 응답
|
||||
*/
|
||||
export interface BomItemResponse {
|
||||
id: number;
|
||||
tenant_id: number;
|
||||
section_id: number;
|
||||
item_code: string | null;
|
||||
item_name: string;
|
||||
quantity: number;
|
||||
unit: string | null;
|
||||
unit_price: number | null;
|
||||
total_price: number | null;
|
||||
spec: string | null;
|
||||
note: string | null;
|
||||
created_by: number | null;
|
||||
updated_by: number | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 섹션 템플릿
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 섹션 템플릿 생성/수정 요청
|
||||
* POST /v1/item-master/section-templates
|
||||
* PUT /v1/item-master/section-templates/{id}
|
||||
*/
|
||||
export interface SectionTemplateRequest {
|
||||
title: string;
|
||||
type: 'fields' | 'bom';
|
||||
description?: string;
|
||||
is_default?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 섹션 템플릿 응답
|
||||
*/
|
||||
export interface SectionTemplateResponse {
|
||||
id: number;
|
||||
tenant_id: number;
|
||||
title: string;
|
||||
type: 'fields' | 'bom';
|
||||
description: string | null;
|
||||
is_default: boolean;
|
||||
created_by: number | null;
|
||||
updated_by: number | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 마스터 필드
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 마스터 필드 생성/수정 요청
|
||||
* POST /v1/item-master/master-fields
|
||||
* PUT /v1/item-master/master-fields/{id}
|
||||
*/
|
||||
export interface MasterFieldRequest {
|
||||
field_name: string;
|
||||
field_type: 'textbox' | 'number' | 'dropdown' | 'checkbox' | 'date' | 'textarea';
|
||||
category?: string;
|
||||
description?: string;
|
||||
is_common?: boolean;
|
||||
default_value?: string;
|
||||
options?: Array<{ label: string; value: string }>;
|
||||
validation_rules?: Record<string, any>;
|
||||
properties?: Record<string, any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 마스터 필드 응답
|
||||
*/
|
||||
export interface MasterFieldResponse {
|
||||
id: number;
|
||||
tenant_id: number;
|
||||
field_name: string;
|
||||
field_type: 'textbox' | 'number' | 'dropdown' | 'checkbox' | 'date' | 'textarea';
|
||||
category: string | null;
|
||||
description: string | null;
|
||||
is_common: boolean;
|
||||
default_value: string | null;
|
||||
options: Array<{ label: string; value: string }> | null;
|
||||
validation_rules: Record<string, any> | null;
|
||||
properties: Record<string, any> | null;
|
||||
created_by: number | null;
|
||||
updated_by: number | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 커스텀 탭
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 커스텀 탭 생성/수정 요청
|
||||
* POST /v1/item-master/custom-tabs
|
||||
* PUT /v1/item-master/custom-tabs/{id}
|
||||
*/
|
||||
export interface CustomTabRequest {
|
||||
label: string;
|
||||
icon?: string;
|
||||
is_default?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 커스텀 탭 응답
|
||||
*/
|
||||
export interface CustomTabResponse {
|
||||
id: number;
|
||||
tenant_id: number;
|
||||
label: string;
|
||||
icon: string | null;
|
||||
is_default: boolean;
|
||||
order_no: number;
|
||||
created_by: number | null;
|
||||
updated_by: number | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 탭 순서 변경 요청
|
||||
* PUT /v1/item-master/custom-tabs/reorder
|
||||
*/
|
||||
export interface TabReorderRequest {
|
||||
tab_orders: Array<{
|
||||
id: number;
|
||||
order_no: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 탭 컬럼 설정 업데이트 요청
|
||||
* PUT /v1/item-master/custom-tabs/{id}/columns
|
||||
*/
|
||||
export interface TabColumnUpdateRequest {
|
||||
columns: Array<{
|
||||
key: string;
|
||||
label: string;
|
||||
visible: boolean;
|
||||
order: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 탭 컬럼 응답
|
||||
*/
|
||||
export interface TabColumnResponse {
|
||||
key: string;
|
||||
label: string;
|
||||
visible: boolean;
|
||||
order: number;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 단위 옵션
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 단위 옵션 생성 요청
|
||||
* POST /v1/item-master/units
|
||||
*/
|
||||
export interface UnitOptionRequest {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 단위 옵션 응답
|
||||
*/
|
||||
export interface UnitOptionResponse {
|
||||
id: number;
|
||||
tenant_id: number;
|
||||
label: string;
|
||||
value: string;
|
||||
created_by: number | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 에러 타입
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* API 에러 응답
|
||||
*/
|
||||
export interface ApiErrorResponse {
|
||||
success: false;
|
||||
message: string;
|
||||
errors?: Record<string, string[]>; // Validation 에러
|
||||
}
|
||||
|
||||
/**
|
||||
* API 에러 클래스용 타입
|
||||
*/
|
||||
export interface ApiErrorData {
|
||||
status: number;
|
||||
message: string;
|
||||
errors?: Record<string, string[]>;
|
||||
}
|
||||
Reference in New Issue
Block a user