# 품목정보 (Item Info) > Screen ID: /screens/140 > 메뉴 경로: 기준정보 > 품목정보 > 테이블: `item_info` ## 1. 테이블 선택 및 화면 구조 ### 1.1 사용 테이블 | 테이블명 | 용도 | 비고 | |----------|------|------| | `item_info` | 품목 기본정보 | 주 테이블 | ### 1.2 테이블 컬럼 정의 (실제 DB 기준) | 컬럼명 | 표시명 | 타입 | 필수 | 설명 | |--------|--------|------|------|------| | `id` | ID | varchar(500) | PK | UUID 자동 생성 | | `item_number` | 품번코드 | varchar(500) | | 품목 고유 코드 | | `item_name` | 품명 | varchar(500) | | 품목명 | | `status` | 상태 | varchar(500) | | 정상, 품절, 대기, 단종 | | `size` | 규격 | varchar(500) | | 규격 정보 | | `material` | 재질 | varchar(500) | | 재질 정보 | | `inventory_unit` | 재고단위 | varchar(500) | | EA, kg, L, Sheet, Box | | `weight` | 중량 | varchar(500) | | 중량 값 | | `unit` | 단위 | varchar(500) | | g, kg, kg/L, t | | `image` | 이미지 | varchar(500) | | 품목 이미지 경로 | | `division` | 구분 | varchar(500) | | 원자재, 중간재, 완제품, 포장재 (카테고리 코드) | | `type` | 유형 | varchar(500) | | 용도별 유형 | | `meno` | 메모 | varchar(500) | | 비고 (오타: memo) | | `selling_price` | 판매가 | varchar(500) | | 기본값 '0' | | `standard_price` | 기준가 | varchar(500) | | 기본값 '0' | | `currency_code` | 통화코드 | varchar(500) | | 기본값 'KRW' | | `writer` | 등록자 | varchar(500) | | 작성자 ID | | `company_code` | 회사코드 | varchar(500) | | 멀티테넌시 | | `created_date` | 등록일 | timestamp | | 자동 생성 | | `updated_date` | 수정일 | timestamp | | 자동 갱신 | ### 1.3 화면 구조 개요 - **화면 유형**: 목록형 (단일 테이블 CRUD) - **주요 기능**: - 품목 조회/검색/필터링 - 품목 등록/수정/삭제 - 그룹핑 (Group By) - 코드 변경/합병 - 엑셀 업로드 - 컬럼 표시/숨기기 설정 --- ## 2. 컴포넌트 배치도 ### 2.1 전체 레이아웃 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ [검색 영역] │ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ v2-table-search-widget │ │ │ │ ┌───────────┐ ┌───────────────┐ ┌───────────────┐ ┌─────────┐ │ │ │ │ │ 상태 │ │ 품번코드 │ │ 품명 │ │ [검색] │ │ │ │ │ │ (select) │ │ (text) │ │ (text) │ │ │ │ │ │ │ └───────────┘ └───────────────┘ └───────────────┘ └─────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────┘ │ ├─────────────────────────────────────────────────────────────────────────────┤ │ [테이블 헤더 + 액션 버튼] │ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ [코드변경][업로드][다운로드] [등록][복사][수정][삭제] │ │ │ └─────────────────────────────────────────────────────────────────────────┘ │ ├─────────────────────────────────────────────────────────────────────────────┤ │ [데이터 테이블] │ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ v2-table-list │ │ │ │ ┌──┬────┬────────┬────────┬──────┬──────┬────────┬─────┬─────┬────────┐ │ │ │ │ │☐ │상태│품번코드│품명 │규격 │재질 │재고단위│중량 │단위 │구분 │ │ │ │ │ ├──┼────┼────────┼────────┼──────┼──────┼────────┼─────┼─────┼────────┤ │ │ │ │ │☐ │정상│R_001 │테스트A │100mm │SUS304│EA │1.5 │kg │원자재 │ │ │ │ │ │☐ │대기│R_002 │테스트B │200mm │AL │kg │2.0 │kg │완제품 │ │ │ │ │ └──┴────┴────────┴────────┴──────┴──────┴────────┴─────┴─────┴────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` ### 2.2 컴포넌트 목록 | 컴포넌트 타입 | 역할 | |---------------|------| | v2-table-search-widget | 검색 필터 | | v2-table-list | 품목 데이터 테이블 | | v2-button-primary | 코드변경 | | v2-button-primary | 업로드 (엑셀) | | v2-button-primary | 다운로드 (엑셀) | | v2-button-primary | 등록 (모달 열기) | | v2-button-primary | 복사 (모달 열기) | | v2-button-primary | 수정 (모달 열기) | | v2-button-primary | 삭제 | --- ## 3. 화면 디자이너 설정 가이드 ### 3.1 v2-table-search-widget (검색 필터) 설정 1. 좌측 컴포넌트 패널에서 `v2-table-search-widget` 드래그하여 화면 상단에 배치 2. 대상 테이블로 아래에 배치할 테이블 리스트 선택 > 💡 **참고**: 검색 필터는 사용자가 런타임에서 원하는 필드를 직접 추가/삭제하여 사용할 수 있습니다. 별도의 필드 설정이 필요 없습니다. --- ### 3.2 v2-table-list (품목 테이블) 설정 #### Step 1: 컴포넌트 추가 1. 좌측 컴포넌트 패널에서 `v2-table-list` 드래그하여 검색 필터 아래에 배치 #### Step 2: 데이터 소스 설정 | 설정 항목 | 설정 값 | |-----------|---------| | 테이블 선택 | `item_info` | | 자동 컬럼 생성 | ✅ 체크 (테이블 컬럼 자동 로드) | #### Step 3: 컬럼 설정 **[컬럼 설정]** 패널에서 표시할 컬럼 선택 및 순서 조정: | 순서 | 컬럼 | 표시명 | 너비 | 정렬 | 표시 | 특수 설정 | |------|------|--------|------|------|------|-----------| | 1 | `status` | 상태 | 80 | 중앙 | ✅ | 뱃지 스타일 (색상별) | | 2 | `item_number` | 품번코드 | 140 | 좌측 | ✅ | | | 3 | `item_name` | 품명 | 200 | 좌측 | ✅ | 굵게 표시 | | 4 | `size` | 규격 | 150 | 좌측 | ✅ | | | 5 | `material` | 재질 | 150 | 좌측 | ✅ | | | 6 | `inventory_unit` | 재고단위 | 100 | 중앙 | ✅ | | | 7 | `weight` | 중량 | 80 | 우측 | ✅ | | | 8 | `unit` | 단위 | 80 | 중앙 | ✅ | | | 9 | `image` | 이미지 | 80 | 중앙 | ✅ | 이미지 미리보기 | | 10 | `division` | 구분 | 100 | 중앙 | ✅ | 카테고리 표시 | | 11 | `type` | 유형 | 100 | 중앙 | ✅ | | | 12 | `selling_price` | 판매가 | 100 | 우측 | ☐ | 숫자 포맷 | | 13 | `standard_price` | 기준가 | 100 | 우측 | ☐ | 숫자 포맷 | | 14 | `meno` | 메모 | 180 | 좌측 | ☐ | | | 15 | `writer` | 등록자 | 100 | 좌측 | ☐ | 읽기 전용 | | 16 | `created_date` | 등록일 | 120 | 중앙 | ☐ | 읽기 전용 | | 17 | `updated_date` | 수정일 | 120 | 중앙 | ☐ | 읽기 전용 | #### Step 4: 기능 설정 | 설정 항목 | 설정 값 | 설명 | |-----------|---------|------| | 체크박스 | ✅ 사용 | 다중 선택 활성화 | | 페이지네이션 | ✅ 사용 | | | 페이지 크기 | 20 | 기본 표시 행 수 | | 정렬 | ✅ 사용 | 컬럼 헤더 클릭 정렬 | | 컬럼 리사이즈 | ✅ 사용 | 컬럼 너비 조정 | | 그룹핑 | ✅ 사용 | Group By 기능 | #### Step 5: 그룹핑 옵션 설정 Group By 드롭다운에 표시할 컬럼 선택: - ✅ `status` (상태) - ✅ `division` (구분) - ✅ `type` (유형) - ✅ `inventory_unit` (재고단위) - ✅ `writer` (등록자) --- ### 3.3 버튼 설정 #### 좌측 버튼 그룹 ##### 코드변경 버튼 | 설정 항목 | 설정 값 | |-----------|---------| | 라벨 | `코드변경` | | 액션 타입 | `code_merge` | | 스타일 | `secondary` | | 선택 필수 | ✅ 체크 (복수 선택) | | 병합 대상 컬럼 | `item_number` | | 데이터플로우 연결 | 품번코드 통합 (flow_id: 18) | ##### 업로드 버튼 | 설정 항목 | 설정 값 | |-----------|---------| | 라벨 | `업로드` | | 액션 타입 | `excel_upload` | | 스타일 | `secondary` | | 대상 테이블 | `item_info` | ##### 다운로드 버튼 | 설정 항목 | 설정 값 | |-----------|---------| | 라벨 | `다운로드` | | 액션 타입 | `excel_download` | | 스타일 | `secondary` | | 대상 | 현재 테이블 리스트 | #### 우측 버튼 그룹 ##### 등록 버튼 | 설정 항목 | 설정 값 | |-----------|---------| | 라벨 | `등록` | | 액션 타입 | `modal` | | 스타일 | `default` | | 연결 화면 | 품목 등록/수정 화면 (아래 3.4 참조) | | 모달 제목 | 품목 등록 | | 모달 사이즈 | `md` | ##### 복사 버튼 | 설정 항목 | 설정 값 | |-----------|---------| | 라벨 | `복사` | | 액션 타입 | `copy` | | 스타일 | `default` | | 선택 필수 | ✅ 체크 (1개만) | | 연결 화면 | 품목 등록/수정 화면 (아래 3.4 참조) | | 동작 | 선택된 데이터를 복사하여 신규 등록 폼에 채움 | ##### 수정 버튼 | 설정 항목 | 설정 값 | |-----------|---------| | 라벨 | `수정` | | 액션 타입 | `edit` | | 스타일 | `default` | | 선택 필수 | ✅ 체크 (1개만) | | 연결 화면 | 품목 등록/수정 화면 (아래 3.4 참조) | | 동작 | 선택된 데이터 수정 모드로 폼 열기 | ##### 삭제 버튼 | 설정 항목 | 설정 값 | |-----------|---------| | 라벨 | `삭제` | | 액션 타입 | `delete` | | 스타일 | `default` | | 선택 필수 | ✅ 체크 (복수 선택 가능) | | 확인 메시지 | 선택한 품목을 삭제하시겠습니까? | | 삭제 후 동작 | 테이블 새로고침 | --- ### 3.4 품목 등록/수정 화면 (모달용 화면) > 📌 **별도 화면 생성 필요**: 등록/복사/수정 버튼에 연결할 모달 화면을 새로 생성합니다. > > 💡 **동일 화면 공유**: 등록, 복사, 수정 버튼 모두 동일한 폼 화면을 사용합니다. > - **등록**: 빈 폼으로 열림 > - **복사**: 선택된 데이터가 채워진 상태로 열림 (신규 등록) > - **수정**: 선택된 데이터가 채워진 상태로 열림 (기존 데이터 업데이트) #### Step 1: 새 화면 생성 1. 화면 관리에서 **[+ 새 화면]** 클릭 2. 화면 정보 입력: - 화면명: `품목 등록/수정` - 테이블: `item_info` - 화면 유형: `모달` #### Step 2: 폼 필드 배치 **모달 레이아웃 배치도**: ``` ┌─────────────────────────────────────────────────────────────┐ │ 품목 등록/수정 [✕] │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────┐ ┌─────────────────────────┐ │ │ │ 품번코드 * │ │ 품명 * │ │ │ │ [____________________] │ │ [____________________] │ │ │ └─────────────────────────┘ └─────────────────────────┘ │ │ │ │ ┌─────────────────────────┐ ┌─────────────────────────┐ │ │ │ 규격 │ │ 재질 │ │ │ │ [____________________] │ │ [____________________] │ │ │ └─────────────────────────┘ └─────────────────────────┘ │ │ │ │ ┌─────────────────────────┐ ┌───────────┐ ┌───────────┐ │ │ │ 재고단위 * │ │ 중량 │ │ 중량단위 │ │ │ │ [EA ▼] │ │ [_______] │ │ [kg ▼] │ │ │ └─────────────────────────┘ └───────────┘ └───────────┘ │ │ │ │ ┌─────────────────────────┐ ┌─────────────────────────┐ │ │ │ 구분 * │ │ 유형 │ │ │ │ [원자재 ▼] │ │ [반도체용 ▼] │ │ │ └─────────────────────────┘ └─────────────────────────┘ │ │ │ │ ┌─────────────────────────┐ ┌─────────────────────────┐ │ │ │ 판매가 │ │ 기준가 │ │ │ │ [____________________] │ │ [____________________] │ │ │ └─────────────────────────┘ └─────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 메모 │ │ │ │ [__________________________________________________]│ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────┐ │ │ │ 상태 * │ │ │ │ [정상 ▼] │ │ │ └─────────────────────────┘ │ │ │ ├─────────────────────────────────────────────────────────────┤ │ [취소] [💾 저장] │ └─────────────────────────────────────────────────────────────┘ ``` **필드 목록**: | 순서 | 필드 (컬럼명) | 라벨 | 입력 타입 | 필수 | 비고 | |------|---------------|------|-----------|------|------| | 1 | `item_number` | 품번코드 | text | ✅ | | | 2 | `item_name` | 품명 | text | ✅ | | | 3 | `size` | 규격 | text | | | | 4 | `material` | 재질 | text | | | | 5 | `inventory_unit` | 재고단위 | select | ✅ | 옵션: EA, kg, L, Sheet, Box | | 6 | `weight` | 중량 | number | | | | 7 | `unit` | 중량단위 | select | | 옵션: g, kg, kg/L, t | | 8 | `division` | 구분 | category | ✅ | 품목 구분 카테고리 | | 9 | `type` | 유형 | select | | 옵션: 반도체용, 태양광용, 산업용, 의료용, 건축용, 사출용, 화장품용 | | 10 | `selling_price` | 판매가 | number | | | | 11 | `standard_price` | 기준가 | number | | | | 12 | `meno` | 메모 | text | | | | 13 | `status` | 상태 | select | ✅ | 옵션: 정상, 품절, 대기, 단종 | #### Step 3: 버튼 배치 | 버튼 | 액션 타입 | 스타일 | 설정 | |------|-----------|--------|------| | 저장 | `저장` | primary | 저장 후 모달 닫기, 부모 화면 테이블 새로고침 | | 취소 | `모달 닫기` | secondary | | #### Step 4: 버튼에 화면 연결 1. 메인 화면(품목정보)으로 돌아가기 2. **등록 버튼** 선택 → 설정 패널에서: - 액션 타입: `modal` - 연결 화면: `품목 등록/수정` 선택 - 모달 제목: `품목 등록` 3. **복사 버튼** 선택 → 설정 패널에서: - 액션 타입: `copy` - 연결 화면: `품목 등록/수정` 선택 - 선택 필수: ✅ 체크 - 동작: 선택된 데이터를 복사하여 폼에 채움 (신규 등록) 4. **수정 버튼** 선택 → 설정 패널에서: - 액션 타입: `edit` - 연결 화면: `품목 등록/수정` 선택 - 선택 필수: ✅ 체크 - 동작: 선택된 데이터를 수정 모드로 폼에 채움 > 💡 **참고**: 컬럼별 스타일(뱃지 색상, 카테고리 표시 등)은 컴포넌트 기본 스타일을 따릅니다. 필요시 테이블 관리에서 컬럼별 상세 설정을 조정할 수 있습니다. --- ## 4. 컴포넌트 연동 설정 ### 4.1 이벤트 흐름 ``` [검색 입력] │ ▼ v2-table-search-widget │ onFilterChange ▼ v2-table-list (자동 재조회) │ ▼ [데이터 표시] [등록/복사/수정 버튼 클릭] │ ▼ [모달 열기] → [폼 입력] → [저장] │ │ │ ▼ │ refreshTable 이벤트 │ │ └────────────────────────┘ │ ▼ v2-table-list (재조회) ``` ### 4.2 연동 설정 | 소스 컴포넌트 | 이벤트/액션 | 대상 컴포넌트 | 동작 | |---------------|-------------|---------------|------| | 검색 위젯 | onFilterChange | 테이블 리스트 | 필터 적용, 재조회 | | 등록 버튼 | click | 모달 | 빈 폼으로 모달 열기 | | 복사 버튼 | click | 모달 | 선택 데이터가 채워진 폼 열기 (신규) | | 수정 버튼 | click | 모달 | 선택 데이터가 채워진 폼 열기 (수정) | | 삭제 버튼 | click | 테이블 리스트 | 선택 항목 삭제 | | 모달 저장 | afterSave | 테이블 리스트 | refreshTable | ### 4.3 TableOptionsContext 연동 ``` v2-table-search-widget ──── TableOptionsContext ──── v2-table-list │ │ │ │ registeredTables에서 │ │ │ item-table 참조 │ │ │ │ │ └── onFilterChange() ───────┼──────────────────────┘ │ ▼ 필터 조건 전달 & 재조회 ``` --- ## 5. 사용자 사용 예시 시나리오 ### 시나리오 1: 품목 조회 | 단계 | 사용자 동작 | 기대 결과 | |------|-------------|-----------| | 1 | 화면 진입 | 전체 품목 목록 표시 | | 2 | 상태 필터를 "정상"으로 선택 | 자동 필터링 | | 3 | 품명에 "폴리머" 입력 후 검색 | 품명에 "폴리머" 포함된 품목 표시 | | 4 | Group by에서 "구분" 선택 | division별 그룹핑 | ### 시나리오 2: 품목 등록 | 단계 | 사용자 동작 | 기대 결과 | |------|-------------|-----------| | 1 | [등록] 버튼 클릭 | 빈 폼 모달 표시 | | 2 | 데이터 입력 (품번코드, 품명, 규격 등) | 입력 필드 채움 | | 3 | [저장] 버튼 클릭 | 저장 완료, 모달 닫힘, 목록 갱신 | ### 시나리오 3: 품목 복사 | 단계 | 사용자 동작 | 기대 결과 | |------|-------------|-----------| | 1 | 테이블에서 복사할 행 체크박스 선택 | 행 선택 표시 | | 2 | [복사] 버튼 클릭 | 선택된 데이터가 채워진 폼 모달 표시 | | 3 | 필요시 데이터 수정 (품번코드 등) | 필드 값 변경 | | 4 | [저장] 버튼 클릭 | 신규 등록 완료, 목록 갱신 | ### 시나리오 4: 품목 수정 | 단계 | 사용자 동작 | 기대 결과 | |------|-------------|-----------| | 1 | 테이블에서 행 체크박스 선택 | 행 선택 표시 | | 2 | [수정] 버튼 클릭 | 수정 모달 표시 (기존 데이터 로드) | | 3 | 데이터 수정 | 필드 값 변경 | | 4 | [저장] 버튼 클릭 | 저장 완료, 목록 갱신 | ### 시나리오 5: 품목 삭제 | 단계 | 사용자 동작 | 기대 결과 | |------|-------------|-----------| | 1 | 삭제할 행 체크박스 선택 (다중 가능) | 행 선택 표시 | | 2 | [삭제] 버튼 클릭 | 삭제 확인 다이얼로그 표시 | | 3 | 확인 | 삭제 완료, 목록 갱신 | --- ## 6. 검증 체크리스트 ### 기본 기능 - [ ] 데이터 조회가 정상 동작하는가? - [ ] 검색 필터 (상태, 품번코드, 품명)가 정상 동작하는가? - [ ] 신규 등록이 정상 동작하는가? - [ ] 복사 기능이 정상 동작하는가? - [ ] 수정이 정상 동작하는가? - [ ] 삭제가 정상 동작하는가? - [ ] 코드변경이 정상 동작하는가? - [ ] 엑셀 업로드가 정상 동작하는가? - [ ] 엑셀 다운로드가 정상 동작하는가? ### 테이블 기능 - [ ] 페이지네이션이 정상 동작하는가? - [ ] 정렬이 정상 동작하는가? - [ ] 컬럼 너비 조정이 정상 동작하는가? - [ ] 체크박스 선택이 정상 동작하는가? ### 검색 위젯 연동 - [ ] v2-table-search-widget과 v2-table-list 연동이 정상 동작하는가? - [ ] 필터 변경 시 자동 재조회가 동작하는가? - [ ] 초기화 버튼이 정상 동작하는가? ### 그룹핑 기능 - [ ] Group by 선택 시 그룹핑이 정상 동작하는가? - [ ] 다중 그룹핑이 정상 동작하는가? --- ## 7. 참고 사항 ### 관련 테이블 - `customer_item_mapping` - 거래처별 품목 매핑 - `supplier_item_mapping` - 공급업체별 품목 매핑 - `item_inspection_info` - 품목 검사 정보 - `item_routing_version` - 품목별 공정 버전 - `item_routing_detail` - 품목별 공정 상세 ### 특이 사항 - `division` 컬럼은 카테고리 코드 (예: CATEGORY_191259)로 저장됨 - `meno` 컬럼은 오타로 보임 (원래 memo) - `selling_price`, `standard_price`는 varchar로 저장됨 (숫자 형식 문자열) - `company_code`는 멀티테넌시용 회사 코드 --- ## 8. DB INSERT용 JSON 설정 (screen_layouts_v2 방식) > 📌 실제 화면 저장은 `screen_definitions` + `screen_layouts_v2` 테이블을 사용합니다. > `screen_layouts_v2`는 전체 레이아웃을 하나의 JSON (`layout_data`)으로 저장합니다. ### 8.1 테이블 구조 #### screen_definitions | 컬럼명 | 타입 | 필수 | 기본값 | 설명 | |--------|------|------|--------|------| | `screen_id` | integer | PK | 자동 생성 (시퀀스) | 화면 고유 ID | | `screen_name` | varchar(100) | ✅ | - | 화면명 | | `screen_code` | varchar(50) | ✅ | **자동 생성** | `{company_code}_{순번}` 형식 | | `table_name` | varchar(100) | | - | 기본 테이블명 | | `company_code` | varchar(50) | ✅ | - | 회사 코드 | | `description` | text | | - | 화면 설명 | | `is_active` | char(1) | | `'Y'` | Y=활성, N=비활성, D=삭제 | | `created_date` | timestamp | | `CURRENT_TIMESTAMP` | 생성일시 | | `db_source_type` | varchar(10) | | `'internal'` | internal/external | | `data_source_type` | varchar(20) | | `'database'` | database/rest_api | #### screen_layouts_v2 | 컬럼명 | 타입 | 필수 | 기본값 | 설명 | |--------|------|------|--------|------| | `layout_id` | integer | PK | 자동 생성 (시퀀스) | 레이아웃 고유 ID | | `screen_id` | integer | ✅ | - | 화면 ID (FK) | | `company_code` | varchar(20) | ✅ | - | 회사 코드 | | `layout_data` | jsonb | ✅ | `'{}'` | 전체 레이아웃 JSON | | `created_at` | timestamp | | `now()` | 생성일시 | | `updated_at` | timestamp | | `now()` | 수정일시 | ### 8.2 화면 정의 (screen_definitions) > ⚠️ `screen_code`는 API 호출 시 자동 생성됩니다. (`{company_code}_{순번}` 형식) **필수 입력 필드:** ```json { "screenName": "품목정보", "tableName": "item_info", "companyCode": "COMPANY_7", "description": "품목 기본정보 관리 화면" } ``` **전체 필드 (자동 생성 포함):** ```json { "screen_id": 140, "screen_name": "품목정보", "screen_code": "COMPANY_7_3", "table_name": "item_info", "company_code": "COMPANY_7", "description": "품목 기본정보 관리 화면", "is_active": "Y", "db_source_type": "internal", "data_source_type": "database", "created_date": "2025-01-29T00:00:00.000Z" } ``` ### 8.2 레이아웃 데이터 (screen_layouts_v2.layout_data) > 전체 레이아웃을 하나의 JSON으로 저장 ```json { "version": "2.0", "components": [ { "id": "comp_search", "url": "@/lib/registry/components/v2-table-search-widget", "size": { "width": 1920, "height": 80 }, "position": { "x": 0, "y": 20, "z": 1 }, "overrides": { "type": "v2-table-search-widget", "label": "검색 필터", "webTypeConfig": {} }, "displayOrder": 0 }, { "id": "comp_table", "url": "@/lib/registry/components/v2-table-list", "size": { "width": 1920, "height": 930 }, "position": { "x": 0, "y": 150, "z": 1 }, "overrides": { "type": "v2-table-list", "label": "테이블 리스트", "filter": { "enabled": true, "filters": [] }, "height": "auto", "actions": { "actions": [], "bulkActions": false, "showActions": false }, "columns": [ { "align": "left", "order": 0, "format": "text", "visible": true, "sortable": true, "columnName": "status", "searchable": true, "displayName": "status" }, { "align": "left", "order": 1, "format": "text", "visible": true, "sortable": true, "columnName": "item_number", "searchable": true, "displayName": "item_number" }, { "align": "left", "order": 2, "format": "text", "visible": true, "sortable": true, "columnName": "item_name", "searchable": true, "displayName": "item_name" }, { "align": "left", "order": 3, "format": "text", "visible": true, "sortable": true, "columnName": "size", "searchable": true, "displayName": "size" }, { "align": "left", "order": 4, "format": "text", "visible": true, "sortable": true, "columnName": "material", "searchable": true, "displayName": "material" }, { "align": "left", "order": 5, "format": "text", "visible": true, "sortable": true, "columnName": "inventory_unit", "searchable": true, "displayName": "inventory_unit" }, { "align": "left", "order": 6, "format": "text", "visible": true, "sortable": true, "columnName": "weight", "searchable": true, "displayName": "weight" }, { "align": "left", "order": 7, "format": "text", "visible": true, "sortable": true, "columnName": "unit", "searchable": true, "displayName": "unit" }, { "align": "left", "order": 8, "format": "text", "visible": true, "sortable": true, "columnName": "division", "searchable": true, "displayName": "division" }, { "align": "left", "order": 9, "format": "text", "visible": true, "sortable": true, "columnName": "type", "searchable": true, "displayName": "type" }, { "align": "left", "order": 10, "format": "text", "visible": true, "sortable": true, "columnName": "writer", "searchable": true, "displayName": "writer" } ], "autoLoad": true, "checkbox": { "enabled": true, "multiple": true, "position": "left", "selectAll": true }, "pagination": { "enabled": true, "pageSize": 20, "showPageInfo": true, "pageSizeOptions": [10, 20, 50, 100], "showSizeSelector": true }, "showFooter": true, "showHeader": true, "tableStyle": { "theme": "default", "rowHeight": "normal", "borderStyle": "light", "headerStyle": "default", "hoverEffect": true, "alternateRows": true }, "displayMode": "table", "stickyHeader": false, "selectedTable": "item_info", "webTypeConfig": {}, "horizontalScroll": { "enabled": true, "maxColumnWidth": 300, "minColumnWidth": 100, "maxVisibleColumns": 8 } }, "displayOrder": 0 }, { "id": "comp_btn_code_merge", "url": "@/lib/registry/components/v2-button-primary", "size": { "width": 88, "height": 40 }, "position": { "x": 10, "y": 100, "z": 1 }, "overrides": { "text": "코드변경", "type": "v2-button-primary", "label": "기본 버튼", "action": { "type": "code_merge", "errorMessage": "저장 중 오류가 발생했습니다.", "successMessage": "저장되었습니다.", "mergeColumnName": "item_number" }, "variant": "primary", "actionType": "button", "webTypeConfig": { "variant": "default", "actionType": "custom", "dataflowConfig": { "flowConfig": { "flowId": 18, "flowName": "품번코드 통합", "contextData": {}, "executionTiming": "after" }, "selectedDiagramId": 18 } } }, "displayOrder": 0 }, { "id": "comp_btn_upload", "url": "@/lib/registry/components/v2-button-primary", "size": { "width": 88, "height": 40 }, "position": { "x": 110, "y": 100, "z": 1 }, "overrides": { "text": "업로드", "type": "v2-button-primary", "label": "기본 버튼", "action": { "type": "excel_upload", "errorMessage": "저장 중 오류가 발생했습니다.", "successMessage": "저장되었습니다." }, "variant": "primary", "actionType": "button", "webTypeConfig": { "variant": "default", "actionType": "custom" } }, "displayOrder": 0 }, { "id": "comp_btn_download", "url": "@/lib/registry/components/v2-button-primary", "size": { "width": 88, "height": 40 }, "position": { "x": 210, "y": 100, "z": 1 }, "overrides": { "text": "다운로드", "type": "v2-button-primary", "label": "기본 버튼", "action": { "type": "excel_download", "errorMessage": "저장 중 오류가 발생했습니다.", "successMessage": "저장되었습니다." }, "variant": "primary", "actionType": "button", "webTypeConfig": { "variant": "default", "actionType": "custom" } }, "displayOrder": 0 }, { "id": "comp_btn_register", "url": "@/lib/registry/components/v2-button-primary", "size": { "width": 80, "height": 40 }, "position": { "x": 1550, "y": 100, "z": 1 }, "overrides": { "text": "등록", "type": "v2-button-primary", "label": "기본 버튼", "action": { "type": "modal", "modalSize": "md", "modalTitle": "품목 등록", "errorMessage": "저장 중 오류가 발생했습니다.", "successMessage": "저장되었습니다.", "targetScreenId": "{{modal_screen_id}}" }, "variant": "primary", "actionType": "button", "webTypeConfig": { "variant": "default", "actionType": "custom" } }, "displayOrder": 0 }, { "id": "comp_btn_copy", "url": "@/lib/registry/components/v2-button-primary", "size": { "width": 80, "height": 40 }, "position": { "x": 1640, "y": 100, "z": 1 }, "overrides": { "text": "복사", "type": "v2-button-primary", "label": "기본 버튼", "action": { "type": "copy", "errorMessage": "저장 중 오류가 발생했습니다.", "successMessage": "저장되었습니다.", "targetScreenId": "{{modal_screen_id}}" }, "variant": "primary", "actionType": "button", "webTypeConfig": { "variant": "default", "actionType": "custom" } }, "displayOrder": 0 }, { "id": "comp_btn_edit", "url": "@/lib/registry/components/v2-button-primary", "size": { "width": 80, "height": 40 }, "position": { "x": 1730, "y": 100, "z": 1 }, "overrides": { "text": "수정", "type": "v2-button-primary", "label": "기본 버튼", "action": { "type": "edit", "errorMessage": "저장 중 오류가 발생했습니다.", "successMessage": "저장되었습니다.", "targetScreenId": "{{modal_screen_id}}" }, "variant": "primary", "actionType": "button", "webTypeConfig": { "variant": "default", "actionType": "custom" } }, "displayOrder": 0 }, { "id": "comp_btn_delete", "url": "@/lib/registry/components/v2-button-primary", "size": { "width": 80, "height": 40 }, "position": { "x": 1820, "y": 100, "z": 1 }, "overrides": { "text": "삭제", "type": "v2-button-primary", "label": "기본 버튼", "action": { "type": "delete", "errorMessage": "저장 중 오류가 발생했습니다.", "successMessage": "저장되었습니다." }, "variant": "primary", "actionType": "button", "webTypeConfig": { "variant": "default", "actionType": "custom" } }, "displayOrder": 0 } ] } ``` ### 8.3 모달 화면 (품목 등록/수정) #### 화면 정의 (필수 입력) ```json { "screenName": "품목 등록/수정", "tableName": "item_info", "companyCode": "COMPANY_7", "description": "품목 등록/수정 폼 화면" } ``` #### 레이아웃 데이터 (screen_layouts_v2.layout_data) ```json { "version": "2.0", "components": [ { "id": "comp_item_number", "url": "@/lib/registry/components/v2-text-input", "size": { "width": 300, "height": 60 }, "position": { "x": 20, "y": 20, "z": 1 }, "overrides": { "type": "v2-text-input", "label": "품번코드", "fieldName": "item_number", "placeholder": "품번코드를 입력하세요", "required": true }, "displayOrder": 0 }, { "id": "comp_item_name", "url": "@/lib/registry/components/v2-text-input", "size": { "width": 300, "height": 60 }, "position": { "x": 340, "y": 20, "z": 1 }, "overrides": { "type": "v2-text-input", "label": "품명", "fieldName": "item_name", "placeholder": "품명을 입력하세요", "required": true }, "displayOrder": 1 }, { "id": "comp_status", "url": "@/lib/registry/components/v2-select-basic", "size": { "width": 300, "height": 60 }, "position": { "x": 20, "y": 100, "z": 1 }, "overrides": { "type": "v2-select-basic", "label": "상태", "fieldName": "status", "options": ["정상", "품절", "대기", "단종"] }, "displayOrder": 2 }, { "id": "comp_btn_save", "url": "@/lib/registry/components/v2-button-primary", "size": { "width": 80, "height": 40 }, "position": { "x": 400, "y": 500, "z": 1 }, "overrides": { "text": "저장", "type": "v2-button-primary", "label": "저장 버튼", "action": { "type": "save", "closeModalAfterSave": true, "refreshParentTable": true, "successMessage": "저장되었습니다.", "errorMessage": "저장 중 오류가 발생했습니다." }, "variant": "primary", "actionType": "button" }, "displayOrder": 20 } ] } ``` ### 8.4 API 호출 방식 > 📌 실제 화면 생성은 API를 통해 진행됩니다. `screen_code`는 서버에서 자동 생성됩니다. #### Step 1: 화면 코드 자동 생성 API ```http GET /api/screens/generate-code?companyCode=COMPANY_7 ``` **응답:** ```json { "success": true, "data": { "screenCode": "COMPANY_7_4" } } ``` #### Step 2: 화면 생성 API ```http POST /api/screens Content-Type: application/json Authorization: Bearer {{token}} { "screenName": "품목정보", "screenCode": "COMPANY_7_4", "tableName": "item_info", "companyCode": "COMPANY_7", "description": "품목 기본정보 관리 화면" } ``` **응답:** ```json { "success": true, "data": { "screenId": 141, "screenCode": "COMPANY_7_4", "screenName": "품목정보" } } ``` #### Step 3: 레이아웃 저장 API ```http PUT /api/screens/141/layout-v2 Content-Type: application/json Authorization: Bearer {{token}} { "layoutData": { "version": "2.0", "components": [ /* 8.2의 components 배열 */ ] } } ``` ### 8.5 SQL 직접 INSERT (참고용) > ⚠️ 일반적으로 API를 사용하지만, 대량 마이그레이션 시 직접 SQL 사용 가능 ```sql -- Step 1: 화면 정의 (screen_code는 수동 지정 필요) INSERT INTO screen_definitions ( screen_name, screen_code, table_name, company_code, description ) VALUES ( '품목정보', 'COMPANY_7_4', 'item_info', 'COMPANY_7', '품목 기본정보 관리 화면' ) RETURNING screen_id; -- Step 2: 레이아웃 저장 (screen_id 사용) INSERT INTO screen_layouts_v2 (screen_id, company_code, layout_data) VALUES ( 141, -- 위에서 반환된 screen_id 'COMPANY_7', '{"version": "2.0", "components": [...]}'::jsonb ); ``` ### 8.6 주의사항 | 항목 | 설명 | |------|------| | `screen_code` | API 사용 시 `generateScreenCode` 먼저 호출, 형식: `{company_code}_{순번}` | | `screen_id` | 화면 생성 후 반환되는 값, 레이아웃 저장 시 필요 | | `component.id` | 고유 ID (UUID 또는 `comp_` prefix), 중복 불가 | | `component.url` | `@/lib/registry/components/v2-xxx` 형식 | | `{{modal_screen_id}}` | 모달 화면 먼저 생성 후 실제 ID로 치환 | | `version` | 반드시 `"2.0"` 사용 | | UNIQUE 제약 | `screen_layouts_v2`는 `(screen_id, company_code)` 조합이 유니크 |