From 4ab2761c826f417933f1a6a275d9686bf4258479 Mon Sep 17 00:00:00 2001 From: kjs Date: Fri, 30 Jan 2026 14:13:44 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20=EB=B9=84=EC=A6=88=EB=8B=88=EC=8A=A4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=9A=94=EC=B2=AD=20=EC=96=91=EC=8B=9D=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EB=B0=8F=20=ED=99=94=EB=A9=B4=20=EB=B6=84?= =?UTF-8?q?=EC=84=9D=20=EC=9A=94=EC=95=BD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 비즈니스 로직 요청 시 필수 양식을 명시하고, 미준수 시 대응 방안을 추가하였습니다. - 전체 화면 분석 요약을 업데이트하여 컴포넌트 커버리지 및 신규 컴포넌트 개발 우선순위를 명확히 하였습니다. - 폴더 구조를 정리하고, 각 컴포넌트의 구현 상태를 표기하여 개발자들이 쉽게 참고할 수 있도록 하였습니다. --- .cursorrules | 43 + db/migrations/so_main_layout.json | 179 +++ db/migrations/so_main_layout_kr.json | 179 +++ db/migrations/so_modal_layout.json | 254 ++++ db/migrations/so_modal_layout_kr.json | 254 ++++ .../00_analysis/full-screen-analysis.md | 331 +++++ .../00_analysis/v2-component-usage-guide.md | 541 +++++++ .../01_master-data/bom.md | 255 ++++ .../02_sales/customer.md | 256 ++++ .../02_sales/order.md | 1276 +++++++++++++++++ .../02_sales/quote.md | 308 ++++ .../03_production/.gitkeep | 0 .../03_production/production-plan.md | 601 ++++++++ .../03_production/work-order.md | 194 +++ .../04_purchase/.gitkeep | 0 .../04_purchase/purchase-order.md | 172 +++ .../05_equipment/.gitkeep | 0 .../05_equipment/equipment-info.md | 244 ++++ .../06_logistics/.gitkeep | 0 .../06_logistics/inout.md | 179 +++ .../07_quality/.gitkeep | 0 .../07_quality/inspection.md | 169 +++ docs/screen-implementation-guide/README.md | 55 +- .../SCREEN_DEVELOPMENT_STANDARD.md | 572 ++++++++ .../화면개발_표준_가이드.md | 706 +++++++++ .../components/screen/ScreenSettingModal.tsx | 11 +- 26 files changed, 6765 insertions(+), 14 deletions(-) create mode 100644 db/migrations/so_main_layout.json create mode 100644 db/migrations/so_main_layout_kr.json create mode 100644 db/migrations/so_modal_layout.json create mode 100644 db/migrations/so_modal_layout_kr.json create mode 100644 docs/screen-implementation-guide/00_analysis/full-screen-analysis.md create mode 100644 docs/screen-implementation-guide/00_analysis/v2-component-usage-guide.md create mode 100644 docs/screen-implementation-guide/01_master-data/bom.md create mode 100644 docs/screen-implementation-guide/02_sales/customer.md create mode 100644 docs/screen-implementation-guide/02_sales/order.md create mode 100644 docs/screen-implementation-guide/02_sales/quote.md create mode 100644 docs/screen-implementation-guide/03_production/.gitkeep create mode 100644 docs/screen-implementation-guide/03_production/production-plan.md create mode 100644 docs/screen-implementation-guide/03_production/work-order.md create mode 100644 docs/screen-implementation-guide/04_purchase/.gitkeep create mode 100644 docs/screen-implementation-guide/04_purchase/purchase-order.md create mode 100644 docs/screen-implementation-guide/05_equipment/.gitkeep create mode 100644 docs/screen-implementation-guide/05_equipment/equipment-info.md create mode 100644 docs/screen-implementation-guide/06_logistics/.gitkeep create mode 100644 docs/screen-implementation-guide/06_logistics/inout.md create mode 100644 docs/screen-implementation-guide/07_quality/.gitkeep create mode 100644 docs/screen-implementation-guide/07_quality/inspection.md create mode 100644 docs/screen-implementation-guide/SCREEN_DEVELOPMENT_STANDARD.md create mode 100644 docs/screen-implementation-guide/화면개발_표준_가이드.md diff --git a/.cursorrules b/.cursorrules index 3b0c3833..77180695 100644 --- a/.cursorrules +++ b/.cursorrules @@ -1,5 +1,48 @@ # Cursor Rules for ERP-node Project +## 🚨 비즈니스 로직 요청 양식 검증 (필수) + +**사용자가 화면 개발 또는 비즈니스 로직 구현을 요청할 때, 아래 양식을 따르지 않으면 반드시 다음과 같이 응답하세요:** + +``` +안녕하세요. Oh My Master! 양식을 못 알아 듣겠습니다. +다시 한번 작성해주십쇼. +=== 비즈니스 로직 요청서 === + +【화면 정보】 +- 화면명: +- 회사코드: +- 메뉴ID (있으면): + +【테이블 정보】 +- 메인 테이블: +- 디테일 테이블 (있으면): +- 관계 FK (있으면): + +【버튼 목록】 +버튼1: + - 버튼명: + - 동작 유형: (저장/삭제/수정/조회/기타) + - 조건 (있으면): + - 대상 테이블: + - 추가 동작 (있으면): + +【추가 요구사항】 +- +``` + +**양식 미준수 판단 기준:** +1. "화면 만들어줘" 같이 테이블명/버튼 정보 없이 요청 +2. "저장하면 저장해줘" 같이 구체적인 테이블/로직 설명 없음 +3. "이전이랑 비슷하게" 같이 모호한 참조 +4. 버튼별 조건/동작이 명시되지 않음 + +**양식 미준수 시 절대 작업 진행하지 말고, 위 양식을 보여주며 다시 작성하라고 요청하세요.** + +**상세 가이드**: [화면개발_표준_가이드.md](docs/screen-implementation-guide/화면개발_표준_가이드.md) + +--- + ## 🚨 최우선 보안 규칙: 멀티테넌시 **모든 코드 작성/수정 완료 후 반드시 다음 파일을 확인하세요:** diff --git a/db/migrations/so_main_layout.json b/db/migrations/so_main_layout.json new file mode 100644 index 00000000..f00aac5a --- /dev/null +++ b/db/migrations/so_main_layout.json @@ -0,0 +1,179 @@ +{ + "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": "Search Filter", + "webTypeConfig": {} + }, + "displayOrder": 0 + }, + { + "id": "comp_table", + "url": "@/lib/registry/components/v2-table-list", + "size": { "width": 1920, "height": 800 }, + "position": { "x": 0, "y": 150, "z": 1 }, + "overrides": { + "type": "v2-table-list", + "label": "Sales Order List", + "filter": { "enabled": true, "filters": [] }, + "height": "auto", + "actions": { "actions": [], "bulkActions": false, "showActions": false }, + "columns": [ + { "align": "left", "order": 0, "format": "text", "visible": true, "sortable": true, "columnName": "order_no", "searchable": true, "displayName": "Order No" }, + { "align": "left", "order": 1, "format": "text", "visible": true, "sortable": true, "columnName": "partner_id", "searchable": true, "displayName": "Customer" }, + { "align": "left", "order": 2, "format": "text", "visible": true, "sortable": true, "columnName": "part_code", "searchable": true, "displayName": "Part Code" }, + { "align": "left", "order": 3, "format": "text", "visible": true, "sortable": true, "columnName": "part_name", "searchable": true, "displayName": "Part Name" }, + { "align": "left", "order": 4, "format": "text", "visible": true, "sortable": true, "columnName": "spec", "searchable": true, "displayName": "Spec" }, + { "align": "left", "order": 5, "format": "text", "visible": true, "sortable": true, "columnName": "material", "searchable": true, "displayName": "Material" }, + { "align": "right", "order": 6, "format": "number", "visible": true, "sortable": true, "columnName": "order_qty", "searchable": false, "displayName": "Order Qty" }, + { "align": "right", "order": 7, "format": "number", "visible": true, "sortable": true, "columnName": "ship_qty", "searchable": false, "displayName": "Ship Qty" }, + { "align": "right", "order": 8, "format": "number", "visible": true, "sortable": true, "columnName": "balance_qty", "searchable": false, "displayName": "Balance" }, + { "align": "right", "order": 9, "format": "number", "visible": true, "sortable": true, "columnName": "inventory_qty", "searchable": false, "displayName": "Stock" }, + { "align": "right", "order": 10, "format": "number", "visible": true, "sortable": true, "columnName": "plan_ship_qty", "searchable": false, "displayName": "Plan Ship Qty" }, + { "align": "right", "order": 11, "format": "number", "visible": true, "sortable": true, "columnName": "unit_price", "searchable": false, "displayName": "Unit Price" }, + { "align": "right", "order": 12, "format": "number", "visible": true, "sortable": true, "columnName": "total_amount", "searchable": false, "displayName": "Amount" }, + { "align": "left", "order": 13, "format": "text", "visible": true, "sortable": true, "columnName": "delivery_partner_id", "searchable": true, "displayName": "Delivery Partner" }, + { "align": "left", "order": 14, "format": "text", "visible": true, "sortable": true, "columnName": "delivery_address", "searchable": true, "displayName": "Delivery Address" }, + { "align": "center", "order": 15, "format": "text", "visible": true, "sortable": true, "columnName": "shipping_method", "searchable": true, "displayName": "Shipping Method" }, + { "align": "center", "order": 16, "format": "date", "visible": true, "sortable": true, "columnName": "due_date", "searchable": false, "displayName": "Due Date" }, + { "align": "center", "order": 17, "format": "date", "visible": true, "sortable": true, "columnName": "order_date", "searchable": false, "displayName": "Order Date" }, + { "align": "center", "order": 18, "format": "text", "visible": true, "sortable": true, "columnName": "status", "searchable": true, "displayName": "Status" }, + { "align": "left", "order": 19, "format": "text", "visible": true, "sortable": true, "columnName": "manager_name", "searchable": true, "displayName": "Manager" }, + { "align": "left", "order": 20, "format": "text", "visible": true, "sortable": true, "columnName": "memo", "searchable": true, "displayName": "Memo" } + ], + "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": "sales_order_mng", + "webTypeConfig": {}, + "horizontalScroll": { "enabled": true, "maxColumnWidth": 300, "minColumnWidth": 80, "maxVisibleColumns": 10 } + }, + "displayOrder": 1 + }, + { + "id": "comp_btn_upload", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 1610, "y": 30, "z": 1 }, + "overrides": { + "text": "Excel Upload", + "type": "v2-button-primary", + "label": "Excel Upload Button", + "action": { "type": "excel_upload" }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 2 + }, + { + "id": "comp_btn_download", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 110, "height": 40 }, + "position": { "x": 1720, "y": 30, "z": 1 }, + "overrides": { + "text": "Excel Download", + "type": "v2-button-primary", + "label": "Excel Download Button", + "action": { "type": "excel_download" }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 3 + }, + { + "id": "comp_btn_register", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 1500, "y": 100, "z": 1 }, + "overrides": { + "text": "New Order", + "type": "v2-button-primary", + "label": "New Order Button", + "action": { + "type": "modal", + "modalSize": "lg", + "modalTitle": "New Sales Order", + "targetScreenId": 3732, + "successMessage": "Saved successfully.", + "errorMessage": "Error saving." + }, + "variant": "success", + "actionType": "button", + "webTypeConfig": { "variant": "default", "actionType": "custom" } + }, + "displayOrder": 4 + }, + { + "id": "comp_btn_edit", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 80, "height": 40 }, + "position": { "x": 1610, "y": 100, "z": 1 }, + "overrides": { + "text": "Edit", + "type": "v2-button-primary", + "label": "Edit Button", + "action": { + "type": "edit", + "modalSize": "lg", + "modalTitle": "Edit Sales Order", + "targetScreenId": 3732, + "successMessage": "Updated successfully.", + "errorMessage": "Error updating." + }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 5 + }, + { + "id": "comp_btn_delete", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 80, "height": 40 }, + "position": { "x": 1700, "y": 100, "z": 1 }, + "overrides": { + "text": "Delete", + "type": "v2-button-primary", + "label": "Delete Button", + "action": { + "type": "delete", + "successMessage": "Deleted successfully.", + "errorMessage": "Error deleting." + }, + "variant": "danger", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 6 + }, + { + "id": "comp_btn_shipment", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 1790, "y": 100, "z": 1 }, + "overrides": { + "text": "Shipment Plan", + "type": "v2-button-primary", + "label": "Shipment Plan Button", + "action": { "type": "custom" }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 7 + } + ] +} diff --git a/db/migrations/so_main_layout_kr.json b/db/migrations/so_main_layout_kr.json new file mode 100644 index 00000000..16361a23 --- /dev/null +++ b/db/migrations/so_main_layout_kr.json @@ -0,0 +1,179 @@ +{ + "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": 800 }, + "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": "order_no", "searchable": true, "displayName": "수주번호" }, + { "align": "left", "order": 1, "format": "text", "visible": true, "sortable": true, "columnName": "partner_id", "searchable": true, "displayName": "거래처" }, + { "align": "left", "order": 2, "format": "text", "visible": true, "sortable": true, "columnName": "part_code", "searchable": true, "displayName": "품목코드" }, + { "align": "left", "order": 3, "format": "text", "visible": true, "sortable": true, "columnName": "part_name", "searchable": true, "displayName": "품명" }, + { "align": "left", "order": 4, "format": "text", "visible": true, "sortable": true, "columnName": "spec", "searchable": true, "displayName": "규격" }, + { "align": "left", "order": 5, "format": "text", "visible": true, "sortable": true, "columnName": "material", "searchable": true, "displayName": "재질" }, + { "align": "right", "order": 6, "format": "number", "visible": true, "sortable": true, "columnName": "order_qty", "searchable": false, "displayName": "수주수량" }, + { "align": "right", "order": 7, "format": "number", "visible": true, "sortable": true, "columnName": "ship_qty", "searchable": false, "displayName": "출하수량" }, + { "align": "right", "order": 8, "format": "number", "visible": true, "sortable": true, "columnName": "balance_qty", "searchable": false, "displayName": "잔량" }, + { "align": "right", "order": 9, "format": "number", "visible": true, "sortable": true, "columnName": "inventory_qty", "searchable": false, "displayName": "현재고" }, + { "align": "right", "order": 10, "format": "number", "visible": true, "sortable": true, "columnName": "plan_ship_qty", "searchable": false, "displayName": "출하계획량" }, + { "align": "right", "order": 11, "format": "number", "visible": true, "sortable": true, "columnName": "unit_price", "searchable": false, "displayName": "단가" }, + { "align": "right", "order": 12, "format": "number", "visible": true, "sortable": true, "columnName": "total_amount", "searchable": false, "displayName": "금액" }, + { "align": "left", "order": 13, "format": "text", "visible": true, "sortable": true, "columnName": "delivery_partner_id", "searchable": true, "displayName": "납품처" }, + { "align": "left", "order": 14, "format": "text", "visible": true, "sortable": true, "columnName": "delivery_address", "searchable": true, "displayName": "납품장소" }, + { "align": "center", "order": 15, "format": "text", "visible": true, "sortable": true, "columnName": "shipping_method", "searchable": true, "displayName": "배송방법" }, + { "align": "center", "order": 16, "format": "date", "visible": true, "sortable": true, "columnName": "due_date", "searchable": false, "displayName": "납기일" }, + { "align": "center", "order": 17, "format": "date", "visible": true, "sortable": true, "columnName": "order_date", "searchable": false, "displayName": "수주일" }, + { "align": "center", "order": 18, "format": "text", "visible": true, "sortable": true, "columnName": "status", "searchable": true, "displayName": "상태" }, + { "align": "left", "order": 19, "format": "text", "visible": true, "sortable": true, "columnName": "manager_name", "searchable": true, "displayName": "담당자" }, + { "align": "left", "order": 20, "format": "text", "visible": true, "sortable": true, "columnName": "memo", "searchable": true, "displayName": "메모" } + ], + "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": "sales_order_mng", + "webTypeConfig": {}, + "horizontalScroll": { "enabled": true, "maxColumnWidth": 300, "minColumnWidth": 80, "maxVisibleColumns": 10 } + }, + "displayOrder": 1 + }, + { + "id": "comp_btn_upload", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 1610, "y": 30, "z": 1 }, + "overrides": { + "text": "엑셀 업로드", + "type": "v2-button-primary", + "label": "엑셀 업로드 버튼", + "action": { "type": "excel_upload" }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 2 + }, + { + "id": "comp_btn_download", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 110, "height": 40 }, + "position": { "x": 1720, "y": 30, "z": 1 }, + "overrides": { + "text": "엑셀 다운로드", + "type": "v2-button-primary", + "label": "엑셀 다운로드 버튼", + "action": { "type": "excel_download" }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 3 + }, + { + "id": "comp_btn_register", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 1500, "y": 100, "z": 1 }, + "overrides": { + "text": "수주 등록", + "type": "v2-button-primary", + "label": "수주 등록 버튼", + "action": { + "type": "modal", + "modalSize": "lg", + "modalTitle": "수주 등록", + "targetScreenId": 3732, + "successMessage": "저장되었습니다.", + "errorMessage": "저장 중 오류가 발생했습니다." + }, + "variant": "success", + "actionType": "button", + "webTypeConfig": { "variant": "default", "actionType": "custom" } + }, + "displayOrder": 4 + }, + { + "id": "comp_btn_edit", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 80, "height": 40 }, + "position": { "x": 1610, "y": 100, "z": 1 }, + "overrides": { + "text": "수정", + "type": "v2-button-primary", + "label": "수정 버튼", + "action": { + "type": "edit", + "modalSize": "lg", + "modalTitle": "수주 수정", + "targetScreenId": 3732, + "successMessage": "수정되었습니다.", + "errorMessage": "수정 중 오류가 발생했습니다." + }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 5 + }, + { + "id": "comp_btn_delete", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 80, "height": 40 }, + "position": { "x": 1700, "y": 100, "z": 1 }, + "overrides": { + "text": "삭제", + "type": "v2-button-primary", + "label": "삭제 버튼", + "action": { + "type": "delete", + "successMessage": "삭제되었습니다.", + "errorMessage": "삭제 중 오류가 발생했습니다." + }, + "variant": "danger", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 6 + }, + { + "id": "comp_btn_shipment", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 1790, "y": 100, "z": 1 }, + "overrides": { + "text": "출하계획", + "type": "v2-button-primary", + "label": "출하계획 버튼", + "action": { "type": "custom" }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 7 + } + ] +} diff --git a/db/migrations/so_modal_layout.json b/db/migrations/so_modal_layout.json new file mode 100644 index 00000000..4245c052 --- /dev/null +++ b/db/migrations/so_modal_layout.json @@ -0,0 +1,254 @@ +{ + "version": "2.0", + "components": [ + { + "id": "comp_order_no", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 20, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "Order No", + "fieldName": "order_no", + "placeholder": "Enter order number", + "required": true + }, + "displayOrder": 0 + }, + { + "id": "comp_order_date", + "url": "@/lib/registry/components/v2-date", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 20, "z": 1 }, + "overrides": { + "type": "v2-date", + "label": "Order Date", + "fieldName": "order_date", + "required": true + }, + "displayOrder": 1 + }, + { + "id": "comp_partner_id", + "url": "@/lib/registry/components/v2-select", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 100, "z": 1 }, + "overrides": { + "type": "v2-select", + "label": "Customer", + "fieldName": "partner_id", + "required": true, + "config": { + "mode": "dropdown", + "source": "table", + "sourceTable": "customer_mng", + "valueField": "id", + "labelField": "name" + } + }, + "displayOrder": 2 + }, + { + "id": "comp_part_code", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 100, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "Part Code", + "fieldName": "part_code", + "placeholder": "Enter part code", + "required": true + }, + "displayOrder": 3 + }, + { + "id": "comp_part_name", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 180, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "Part Name", + "fieldName": "part_name", + "placeholder": "Enter part name" + }, + "displayOrder": 4 + }, + { + "id": "comp_spec", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 180, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "Spec", + "fieldName": "spec", + "placeholder": "Enter spec" + }, + "displayOrder": 5 + }, + { + "id": "comp_material", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 260, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "Material", + "fieldName": "material", + "placeholder": "Enter material" + }, + "displayOrder": 6 + }, + { + "id": "comp_order_qty", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 260, "z": 1 }, + "overrides": { + "type": "v2-input", + "inputType": "number", + "label": "Order Qty", + "fieldName": "order_qty", + "placeholder": "Enter order quantity", + "required": true + }, + "displayOrder": 7 + }, + { + "id": "comp_unit_price", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 340, "z": 1 }, + "overrides": { + "type": "v2-input", + "inputType": "number", + "label": "Unit Price", + "fieldName": "unit_price", + "placeholder": "Enter unit price", + "required": true + }, + "displayOrder": 8 + }, + { + "id": "comp_due_date", + "url": "@/lib/registry/components/v2-date", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 340, "z": 1 }, + "overrides": { + "type": "v2-date", + "label": "Due Date", + "fieldName": "due_date" + }, + "displayOrder": 9 + }, + { + "id": "comp_status", + "url": "@/lib/registry/components/v2-select", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 420, "z": 1 }, + "overrides": { + "type": "v2-select", + "label": "Status", + "fieldName": "status", + "required": true, + "config": { + "mode": "dropdown", + "source": "static", + "options": [ + { "value": "수주", "label": "수주" }, + { "value": "진행중", "label": "진행중" }, + { "value": "완료", "label": "완료" }, + { "value": "취소", "label": "취소" } + ] + } + }, + "displayOrder": 10 + }, + { + "id": "comp_shipping_method", + "url": "@/lib/registry/components/v2-select", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 420, "z": 1 }, + "overrides": { + "type": "v2-select", + "label": "Shipping Method", + "fieldName": "shipping_method", + "config": { + "mode": "dropdown", + "source": "static", + "options": [ + { "value": "택배", "label": "택배" }, + { "value": "화물", "label": "화물" }, + { "value": "직송", "label": "직송" }, + { "value": "퀵서비스", "label": "퀵서비스" }, + { "value": "해상운송", "label": "해상운송" } + ] + } + }, + "displayOrder": 11 + }, + { + "id": "comp_delivery_address", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 620, "height": 60 }, + "position": { "x": 20, "y": 500, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "Delivery Address", + "fieldName": "delivery_address", + "placeholder": "Enter delivery address" + }, + "displayOrder": 12 + }, + { + "id": "comp_manager_name", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 580, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "Manager", + "fieldName": "manager_name", + "placeholder": "Enter manager name" + }, + "displayOrder": 13 + }, + { + "id": "comp_memo", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 620, "height": 80 }, + "position": { "x": 20, "y": 660, "z": 1 }, + "overrides": { + "type": "v2-input", + "inputType": "textarea", + "label": "Memo", + "fieldName": "memo", + "placeholder": "Enter memo" + }, + "displayOrder": 14 + }, + { + "id": "comp_btn_save", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 540, "y": 760, "z": 1 }, + "overrides": { + "text": "Save", + "type": "v2-button-primary", + "label": "Save Button", + "action": { + "type": "save", + "closeModalAfterSave": true, + "refreshParentTable": true, + "successMessage": "Saved successfully.", + "errorMessage": "Error saving." + }, + "variant": "primary", + "actionType": "button" + }, + "displayOrder": 15 + } + ] +} diff --git a/db/migrations/so_modal_layout_kr.json b/db/migrations/so_modal_layout_kr.json new file mode 100644 index 00000000..f07e3ae6 --- /dev/null +++ b/db/migrations/so_modal_layout_kr.json @@ -0,0 +1,254 @@ +{ + "version": "2.0", + "components": [ + { + "id": "comp_order_no", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 20, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "수주번호", + "fieldName": "order_no", + "placeholder": "수주번호를 입력하세요", + "required": true + }, + "displayOrder": 0 + }, + { + "id": "comp_order_date", + "url": "@/lib/registry/components/v2-date", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 20, "z": 1 }, + "overrides": { + "type": "v2-date", + "label": "수주일", + "fieldName": "order_date", + "required": true + }, + "displayOrder": 1 + }, + { + "id": "comp_partner_id", + "url": "@/lib/registry/components/v2-select", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 100, "z": 1 }, + "overrides": { + "type": "v2-select", + "label": "거래처", + "fieldName": "partner_id", + "required": true, + "config": { + "mode": "dropdown", + "source": "table", + "sourceTable": "customer_mng", + "valueField": "id", + "labelField": "name" + } + }, + "displayOrder": 2 + }, + { + "id": "comp_part_code", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 100, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "품목코드", + "fieldName": "part_code", + "placeholder": "품목코드를 입력하세요", + "required": true + }, + "displayOrder": 3 + }, + { + "id": "comp_part_name", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 180, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "품명", + "fieldName": "part_name", + "placeholder": "품명을 입력하세요" + }, + "displayOrder": 4 + }, + { + "id": "comp_spec", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 180, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "규격", + "fieldName": "spec", + "placeholder": "규격을 입력하세요" + }, + "displayOrder": 5 + }, + { + "id": "comp_material", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 260, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "재질", + "fieldName": "material", + "placeholder": "재질을 입력하세요" + }, + "displayOrder": 6 + }, + { + "id": "comp_order_qty", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 260, "z": 1 }, + "overrides": { + "type": "v2-input", + "inputType": "number", + "label": "수주수량", + "fieldName": "order_qty", + "placeholder": "수주수량을 입력하세요", + "required": true + }, + "displayOrder": 7 + }, + { + "id": "comp_unit_price", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 340, "z": 1 }, + "overrides": { + "type": "v2-input", + "inputType": "number", + "label": "단가", + "fieldName": "unit_price", + "placeholder": "단가를 입력하세요", + "required": true + }, + "displayOrder": 8 + }, + { + "id": "comp_due_date", + "url": "@/lib/registry/components/v2-date", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 340, "z": 1 }, + "overrides": { + "type": "v2-date", + "label": "납기일", + "fieldName": "due_date" + }, + "displayOrder": 9 + }, + { + "id": "comp_status", + "url": "@/lib/registry/components/v2-select", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 420, "z": 1 }, + "overrides": { + "type": "v2-select", + "label": "상태", + "fieldName": "status", + "required": true, + "config": { + "mode": "dropdown", + "source": "static", + "options": [ + { "value": "수주", "label": "수주" }, + { "value": "진행중", "label": "진행중" }, + { "value": "완료", "label": "완료" }, + { "value": "취소", "label": "취소" } + ] + } + }, + "displayOrder": 10 + }, + { + "id": "comp_shipping_method", + "url": "@/lib/registry/components/v2-select", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 420, "z": 1 }, + "overrides": { + "type": "v2-select", + "label": "배송방법", + "fieldName": "shipping_method", + "config": { + "mode": "dropdown", + "source": "static", + "options": [ + { "value": "택배", "label": "택배" }, + { "value": "화물", "label": "화물" }, + { "value": "직송", "label": "직송" }, + { "value": "퀵서비스", "label": "퀵서비스" }, + { "value": "해상운송", "label": "해상운송" } + ] + } + }, + "displayOrder": 11 + }, + { + "id": "comp_delivery_address", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 620, "height": 60 }, + "position": { "x": 20, "y": 500, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "납품장소", + "fieldName": "delivery_address", + "placeholder": "납품장소를 입력하세요" + }, + "displayOrder": 12 + }, + { + "id": "comp_manager_name", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 580, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "담당자", + "fieldName": "manager_name", + "placeholder": "담당자를 입력하세요" + }, + "displayOrder": 13 + }, + { + "id": "comp_memo", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 620, "height": 80 }, + "position": { "x": 20, "y": 660, "z": 1 }, + "overrides": { + "type": "v2-input", + "inputType": "textarea", + "label": "메모", + "fieldName": "memo", + "placeholder": "메모를 입력하세요" + }, + "displayOrder": 14 + }, + { + "id": "comp_btn_save", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 540, "y": 760, "z": 1 }, + "overrides": { + "text": "저장", + "type": "v2-button-primary", + "label": "저장 버튼", + "action": { + "type": "save", + "closeModalAfterSave": true, + "refreshParentTable": true, + "successMessage": "저장되었습니다.", + "errorMessage": "저장 중 오류가 발생했습니다." + }, + "variant": "primary", + "actionType": "button" + }, + "displayOrder": 15 + } + ] +} diff --git a/docs/screen-implementation-guide/00_analysis/full-screen-analysis.md b/docs/screen-implementation-guide/00_analysis/full-screen-analysis.md new file mode 100644 index 00000000..9b4a9908 --- /dev/null +++ b/docs/screen-implementation-guide/00_analysis/full-screen-analysis.md @@ -0,0 +1,331 @@ +# 화면 전체 분석 보고서 + +> **분석 대상**: `/Users/kimjuseok/Downloads/화면개발 8` 폴더 내 핵심 업무 화면 +> **분석 기준**: 메뉴별 분류, 3개 이상 재활용 가능한 컴포넌트 식별 +> **분석 일자**: 2026-01-30 + +--- + +## 1. 현재 사용 중인 V2 컴포넌트 목록 + +> **중요**: v2- 접두사가 붙은 컴포넌트만 사용합니다. + +### 입력 컴포넌트 +| ID | 이름 | 용도 | +|----|------|------| +| `v2-input` | V2 입력 | 텍스트, 숫자, 비밀번호, 이메일 등 입력 | +| `v2-select` | V2 선택 | 드롭다운, 콤보박스, 라디오, 체크박스 | +| `v2-date` | V2 날짜 | 날짜, 시간, 날짜범위 입력 | + +### 표시 컴포넌트 +| ID | 이름 | 용도 | +|----|------|------| +| `v2-text-display` | 텍스트 표시 | 라벨, 텍스트 표시 | +| `v2-card-display` | 카드 디스플레이 | 테이블 데이터를 카드 형태로 표시 | +| `v2-aggregation-widget` | 집계 위젯 | 합계, 평균, 개수 등 집계 표시 | + +### 테이블/데이터 컴포넌트 +| ID | 이름 | 용도 | +|----|------|------| +| `v2-table-list` | 테이블 리스트 | 데이터 테이블 표시, 페이지네이션, 정렬, 필터 | +| `v2-table-search-widget` | 검색 필터 | 화면 내 테이블 검색/필터/그룹 기능 | +| `v2-pivot-grid` | 피벗 그리드 | 다차원 데이터 분석 (피벗 테이블) | + +### 레이아웃 컴포넌트 +| ID | 이름 | 용도 | +|----|------|------| +| `v2-split-panel-layout` | 분할 패널 | 마스터-디테일 좌우 분할 레이아웃 | +| `v2-tabs-widget` | 탭 위젯 | 탭 전환, 탭 내 컴포넌트 배치 | +| `v2-section-card` | Section Card | 제목/테두리가 있는 그룹화 컨테이너 | +| `v2-section-paper` | Section Paper | 배경색 기반 미니멀 그룹화 컨테이너 | +| `v2-divider-line` | 구분선 | 영역 구분 | +| `v2-repeat-container` | 리피터 컨테이너 | 데이터 수만큼 내부 컴포넌트 반복 렌더링 | +| `v2-repeater` | 리피터 | 반복 컨트롤 | + +### 액션/기타 컴포넌트 +| ID | 이름 | 용도 | +|----|------|------| +| `v2-button-primary` | 기본 버튼 | 저장, 삭제 등 액션 버튼 | +| `v2-numbering-rule` | 채번규칙 | 자동 코드/번호 생성 | +| `v2-category-manager` | 카테고리 관리자 | 카테고리 관리 | +| `v2-location-swap-selector` | 위치 교환 선택기 | 위치 교환 기능 | +| `v2-rack-structure` | 랙 구조 | 창고 랙 시각화 | +| `v2-media` | 미디어 | 미디어 표시 | + +**총 23개 V2 컴포넌트** + +--- + +## 2. 화면 분류 (메뉴별) + +### 01. 기준정보 (master-data) +| 화면명 | 파일명 | 패턴 | 구현 가능 | +|--------|--------|------|----------| +| 회사정보 | 회사정보.html | 검색+테이블 | ✅ 완전 | +| 부서정보 | 부서정보.html | 검색+테이블 | ✅ 완전 | +| 품목정보 | 품목정보.html | 검색+테이블+그룹화 | ⚠️ 그룹화 미지원 | +| BOM관리 | BOM관리.html | 분할패널+트리 | ⚠️ 트리뷰 미지원 | +| 공정정보관리 | 공정정보관리.html | 분할패널+테이블 | ✅ 완전 | +| 공정작업기준 | 공정작업기준관리.html | 검색+테이블 | ✅ 완전 | +| 품목라우팅 | 품목라우팅관리.html | 분할패널+테이블 | ✅ 완전 | + +### 02. 영업관리 (sales) +| 화면명 | 파일명 | 패턴 | 구현 가능 | +|--------|--------|------|----------| +| 수주관리 | 수주관리.html | 분할패널+테이블 | ✅ 완전 | +| 견적관리 | 견적관리.html | 분할패널+테이블 | ✅ 완전 | +| 거래처관리 | 거래처관리.html | 분할패널+탭+그룹화 | ⚠️ 그룹화 미지원 | +| 판매품목정보 | 판매품목정보.html | 검색+테이블 | ✅ 완전 | +| 출하계획관리 | 출하계획관리.html | 검색+테이블 | ✅ 완전 | + +### 03. 생산관리 (production) +| 화면명 | 파일명 | 패턴 | 구현 가능 | +|--------|--------|------|----------| +| 생산계획관리 | 생산계획관리.html | 분할패널+탭+타임라인 | ❌ 타임라인 미지원 | +| 생산관리 | 생산관리.html | 검색+테이블 | ✅ 완전 | +| 생산실적관리 | 생산실적관리.html | 검색+테이블 | ✅ 완전 | +| 작업지시 | 작업지시.html | 탭+그룹화테이블+분할패널 | ⚠️ 그룹화 미지원 | +| 공정관리 | 공정관리.html | 분할패널+테이블 | ✅ 완전 | + +### 04. 구매관리 (purchase) +| 화면명 | 파일명 | 패턴 | 구현 가능 | +|--------|--------|------|----------| +| 발주관리 | 발주관리.html | 검색+테이블 | ✅ 완전 | +| 공급업체관리 | 공급업체관리.html | 검색+테이블 | ✅ 완전 | +| 구매입고 | pages/구매입고.html | 검색+테이블 | ✅ 완전 | + +### 05. 설비관리 (equipment) +| 화면명 | 파일명 | 패턴 | 구현 가능 | +|--------|--------|------|----------| +| 설비정보 | 설비정보.html | 분할패널+카드+탭 | ✅ v2-card-display 활용 | + +### 06. 물류관리 (logistics) +| 화면명 | 파일명 | 패턴 | 구현 가능 | +|--------|--------|------|----------| +| 창고관리 | 창고관리.html | 모바일앱스타일+iframe | ❌ 별도개발 필요 | +| 창고정보관리 | 창고정보관리.html | 검색+테이블 | ✅ 완전 | +| 입출고관리 | 입출고관리.html | 검색+테이블+그룹화 | ⚠️ 그룹화 미지원 | +| 재고현황 | 재고현황.html | 검색+테이블 | ✅ 완전 | + +### 07. 품질관리 (quality) +| 화면명 | 파일명 | 패턴 | 구현 가능 | +|--------|--------|------|----------| +| 검사기준 | 검사기준.html | 검색+테이블 | ✅ 완전 | +| 검사정보관리 | 검사정보관리.html | 탭+테이블 | ✅ 완전 | +| 검사장비관리 | 검사장비관리.html | 검색+테이블 | ✅ 완전 | +| 불량관리 | 불량관리.html | 검색+테이블 | ✅ 완전 | +| 클레임관리 | 클레임관리.html | 검색+테이블 | ✅ 완전 | + +--- + +## 3. 화면 UI 패턴 분석 + +### 패턴 A: 검색 + 테이블 (가장 기본) +**해당 화면**: 약 60% (15개 이상) + +**사용 컴포넌트**: +- `v2-table-search-widget`: 검색 필터 +- `v2-table-list`: 데이터 테이블 + +``` +┌─────────────────────────────────────────┐ +│ [검색필드들...] [조회] [엑셀] │ ← v2-table-search-widget +├─────────────────────────────────────────┤ +│ 테이블 제목 [신규등록] [삭제] │ +│ ────────────────────────────────────── │ +│ □ | 코드 | 이름 | 상태 | 등록일 | │ ← v2-table-list +│ □ | A001 | 테스트| 사용 | 2026-01-30 | │ +└─────────────────────────────────────────┘ +``` + +### 패턴 B: 분할 패널 (마스터-디테일) +**해당 화면**: 약 25% (8개) + +**사용 컴포넌트**: +- `v2-split-panel-layout`: 좌우 분할 +- `v2-table-list`: 마스터/디테일 테이블 +- `v2-tabs-widget`: 상세 탭 (선택) + +``` +┌──────────────────┬──────────────────────┐ +│ 마스터 리스트 │ 상세 정보 / 탭 │ +│ ─────────────── │ ┌────┬────┬────┐ │ +│ □ A001 제품A │ │기본│이력│첨부│ │ +│ □ A002 제품B ← │ └────┴────┴────┘ │ +│ □ A003 제품C │ [테이블 or 폼] │ +└──────────────────┴──────────────────────┘ +``` + +### 패턴 C: 탭 + 테이블 +**해당 화면**: 약 10% (3개) + +**사용 컴포넌트**: +- `v2-tabs-widget`: 탭 전환 +- `v2-table-list`: 탭별 테이블 + +``` +┌─────────────────────────────────────────┐ +│ [탭1] [탭2] [탭3] │ +├─────────────────────────────────────────┤ +│ [테이블 영역] │ +└─────────────────────────────────────────┘ +``` + +### 패턴 D: 특수 UI +**해당 화면**: 약 5% (2개) + +- 생산계획관리: 타임라인/간트 차트 → **v2-timeline 미존재** +- 창고관리: 모바일 앱 스타일 → **별도 개발 필요** + +--- + +## 4. 신규 컴포넌트 분석 (3개 이상 재활용 기준) + +### 4.1 v2-grouped-table (그룹화 테이블) +**재활용 화면 수**: 5개 이상 ✅ + +| 화면 | 그룹화 기준 | +|------|------------| +| 품목정보 | 품목구분, 카테고리 | +| 거래처관리 | 거래처유형, 지역 | +| 작업지시 | 작업일자, 공정 | +| 입출고관리 | 입출고구분, 창고 | +| 견적관리 | 상태, 거래처 | + +**기능 요구사항**: +- 특정 컬럼 기준 그룹핑 +- 그룹 접기/펼치기 +- 그룹 헤더에 집계 표시 +- 다중 그룹핑 지원 + +**구현 복잡도**: 중 + +### 4.2 v2-tree-view (트리 뷰) +**재활용 화면 수**: 3개 ✅ + +| 화면 | 트리 용도 | +|------|----------| +| BOM관리 | BOM 구조 (정전개/역전개) | +| 부서정보 | 조직도 | +| 메뉴관리 | 메뉴 계층 | + +**기능 요구사항**: +- 노드 접기/펼치기 +- 드래그앤드롭 (선택) +- 정전개/역전개 전환 +- 노드 선택 이벤트 + +**구현 복잡도**: 중상 + +### 4.3 v2-timeline-scheduler (타임라인) +**재활용 화면 수**: 1~2개 (기준 미달) + +| 화면 | 용도 | +|------|------| +| 생산계획관리 | 간트 차트 | +| 설비 가동 현황 | 타임라인 | + +**기능 요구사항**: +- 시간축 기반 배치 +- 드래그로 일정 변경 +- 공정별 색상 구분 +- 줌 인/아웃 + +**구현 복잡도**: 상 + +> **참고**: 3개 미만이므로 우선순위 하향 + +--- + +## 5. 컴포넌트 커버리지 + +### 현재 V2 컴포넌트로 구현 가능 +``` +┌─────────────────────────────────────────────────┐ +│ 17개 화면 (65%) │ +│ - 기본 검색 + 테이블 패턴 │ +│ - 분할 패널 │ +│ - 탭 전환 │ +│ - 카드 디스플레이 │ +└─────────────────────────────────────────────────┘ +``` + +### v2-grouped-table 개발 후 +``` +┌─────────────────────────────────────────────────┐ +│ +5개 화면 (22개, 85%) │ +│ - 품목정보, 거래처관리, 작업지시 │ +│ - 입출고관리, 견적관리 │ +└─────────────────────────────────────────────────┘ +``` + +### v2-tree-view 개발 후 +``` +┌─────────────────────────────────────────────────┐ +│ +2개 화면 (24개, 92%) │ +│ - BOM관리, 부서정보(계층) │ +└─────────────────────────────────────────────────┘ +``` + +### 별도 개발 필요 +``` +┌─────────────────────────────────────────────────┐ +│ 2개 화면 (8%) │ +│ - 생산계획관리 (타임라인) │ +│ - 창고관리 (모바일 앱 스타일) │ +└─────────────────────────────────────────────────┘ +``` + +--- + +## 6. 신규 컴포넌트 개발 우선순위 + +| 순위 | 컴포넌트 | 재활용 화면 수 | 복잡도 | ROI | +|------|----------|--------------|--------|-----| +| 1 | v2-grouped-table | 5+ | 중 | ⭐⭐⭐⭐⭐ | +| 2 | v2-tree-view | 3 | 중상 | ⭐⭐⭐⭐ | +| 3 | v2-timeline-scheduler | 1~2 | 상 | ⭐⭐ | + +--- + +## 7. 권장 구현 전략 + +### Phase 1: 즉시 구현 (현재 V2 컴포넌트) +- 회사정보, 부서정보 +- 발주관리, 공급업체관리 +- 검사기준, 검사장비관리, 불량관리 +- 창고정보관리, 재고현황 +- 공정작업기준관리 +- 수주관리, 견적관리, 공정관리 +- 설비정보 (v2-card-display 활용) +- 검사정보관리 + +### Phase 2: v2-grouped-table 개발 후 +- 품목정보, 거래처관리, 입출고관리 +- 작업지시 + +### Phase 3: v2-tree-view 개발 후 +- BOM관리 +- 부서정보 (계층 뷰) + +### Phase 4: 개별 개발 +- 생산계획관리 (타임라인) +- 창고관리 (모바일 스타일) + +--- + +## 8. 요약 + +| 항목 | 수치 | +|------|------| +| 전체 분석 화면 수 | 26개 | +| 현재 즉시 구현 가능 | 17개 (65%) | +| v2-grouped-table 추가 시 | 22개 (85%) | +| v2-tree-view 추가 시 | 24개 (92%) | +| 별도 개발 필요 | 2개 (8%) | + +**핵심 결론**: +1. **현재 V2 컴포넌트**로 65% 화면 구현 가능 +2. **v2-grouped-table** 1개 컴포넌트 개발로 85%까지 확대 +3. **v2-tree-view** 추가로 92% 도달 +4. 나머지 8%는 화면별 특수 UI (타임라인, 모바일 스타일)로 개별 개발 필요 diff --git a/docs/screen-implementation-guide/00_analysis/v2-component-usage-guide.md b/docs/screen-implementation-guide/00_analysis/v2-component-usage-guide.md new file mode 100644 index 00000000..1f18e804 --- /dev/null +++ b/docs/screen-implementation-guide/00_analysis/v2-component-usage-guide.md @@ -0,0 +1,541 @@ +# V2 공통 컴포넌트 사용 가이드 + +> **목적**: 다양한 회사에서 V2 컴포넌트를 활용하여 화면을 개발할 때 참고하는 범용 가이드 +> **대상**: 화면 설계자, 개발자 +> **버전**: 1.0.0 +> **작성일**: 2026-01-30 + +--- + +## 1. V2 컴포넌트로 가능한 것 / 불가능한 것 + +### 1.1 가능한 화면 유형 + +| 화면 유형 | 설명 | 대표 예시 | +|-----------|------|----------| +| 마스터 관리 | 단일 테이블 CRUD | 회사정보, 부서정보, 코드관리 | +| 마스터-디테일 | 좌측 선택 → 우측 상세 | 공정관리, 품목라우팅, 견적관리 | +| 탭 기반 화면 | 탭별 다른 테이블/뷰 | 검사정보관리, 거래처관리 | +| 카드 뷰 | 이미지+정보 카드 형태 | 설비정보, 대시보드 | +| 피벗 분석 | 다차원 집계 | 매출분석, 재고현황 | +| 반복 컨테이너 | 데이터 수만큼 UI 반복 | 주문 상세, 항목 리스트 | + +### 1.2 불가능한 화면 유형 (별도 개발 필요) + +| 화면 유형 | 이유 | 해결 방안 | +|-----------|------|----------| +| 간트 차트 / 타임라인 | 시간축 기반 UI 없음 | 별도 컴포넌트 개발 or 외부 라이브러리 | +| 트리 뷰 (계층 구조) | 트리 컴포넌트 미존재 | `v2-tree-view` 개발 필요 | +| 그룹화 테이블 | 그룹핑 기능 미지원 | `v2-grouped-table` 개발 필요 | +| 드래그앤드롭 보드 | 칸반 스타일 UI 없음 | 별도 개발 | +| 모바일 앱 스타일 | 네이티브 앱 UI | 별도 개발 | +| 복잡한 차트 | 기본 집계 외 시각화 | 차트 라이브러리 연동 | + +--- + +## 2. V2 컴포넌트 전체 목록 (23개) + +### 2.1 입력 컴포넌트 (3개) + +| ID | 이름 | 용도 | 주요 옵션 | +|----|------|------|----------| +| `v2-input` | 입력 | 텍스트, 숫자, 비밀번호, 이메일, 전화번호, URL, 여러 줄 | inputType, required, readonly, maxLength | +| `v2-select` | 선택 | 드롭다운, 콤보박스, 라디오, 체크박스 | mode, source(distinct/static/code/entity), multiple | +| `v2-date` | 날짜 | 날짜, 시간, 날짜시간, 날짜범위, 월, 연도 | dateType, format, showTime | + +### 2.2 표시 컴포넌트 (3개) + +| ID | 이름 | 용도 | 주요 옵션 | +|----|------|------|----------| +| `v2-text-display` | 텍스트 표시 | 라벨, 제목, 설명 텍스트 | fontSize, fontWeight, color, textAlign | +| `v2-card-display` | 카드 디스플레이 | 테이블 데이터를 카드 형태로 표시 | cardsPerRow, showImage, columnMapping | +| `v2-aggregation-widget` | 집계 위젯 | 합계, 평균, 개수, 최대, 최소 | items, filters, layout | + +### 2.3 테이블/데이터 컴포넌트 (3개) + +| ID | 이름 | 용도 | 주요 옵션 | +|----|------|------|----------| +| `v2-table-list` | 테이블 리스트 | 데이터 조회/편집 테이블 | selectedTable, columns, pagination, filter | +| `v2-table-search-widget` | 검색 필터 | 테이블 검색/필터/그룹 | autoSelectFirstTable, showTableSelector | +| `v2-pivot-grid` | 피벗 그리드 | 다차원 분석 (행/열/데이터 영역) | fields, totals, aggregation | + +### 2.4 레이아웃 컴포넌트 (8개) + +| ID | 이름 | 용도 | 주요 옵션 | +|----|------|------|----------| +| `v2-split-panel-layout` | 분할 패널 | 마스터-디테일 좌우 분할 | splitRatio, resizable, relation | +| `v2-tabs-widget` | 탭 위젯 | 탭 전환, 탭 내 컴포넌트 | tabs, activeTabId | +| `v2-section-card` | 섹션 카드 | 제목+테두리 그룹화 | title, collapsible, padding | +| `v2-section-paper` | 섹션 페이퍼 | 배경색 그룹화 | backgroundColor, padding, shadow | +| `v2-divider-line` | 구분선 | 영역 구분 | orientation, thickness | +| `v2-repeat-container` | 리피터 컨테이너 | 데이터 수만큼 반복 렌더링 | dataSourceType, layout, gridColumns | +| `v2-repeater` | 리피터 | 반복 컨트롤 | - | +| `v2-repeat-screen-modal` | 반복 화면 모달 | 모달 반복 | - | + +### 2.5 액션/특수 컴포넌트 (6개) + +| ID | 이름 | 용도 | 주요 옵션 | +|----|------|------|----------| +| `v2-button-primary` | 기본 버튼 | 저장, 삭제 등 액션 | text, actionType, variant | +| `v2-numbering-rule` | 채번규칙 | 자동 코드/번호 생성 | rule, prefix, format | +| `v2-category-manager` | 카테고리 관리자 | 카테고리 관리 UI | - | +| `v2-location-swap-selector` | 위치 교환 | 위치 선택/교환 | - | +| `v2-rack-structure` | 랙 구조 | 창고 랙 시각화 | - | +| `v2-media` | 미디어 | 이미지/동영상 표시 | - | + +--- + +## 3. 화면 패턴별 컴포넌트 조합 + +### 3.1 패턴 A: 기본 마스터 화면 (가장 흔함) + +**적용 화면**: 코드관리, 사용자관리, 부서정보, 창고정보 등 + +``` +┌─────────────────────────────────────────────────┐ +│ v2-table-search-widget │ +│ [검색필드1] [검색필드2] [조회] [엑셀] │ +├─────────────────────────────────────────────────┤ +│ v2-table-list │ +│ 제목 [신규] [삭제] │ +│ ─────────────────────────────────────────────── │ +│ □ | 코드 | 이름 | 상태 | 등록일 | │ +└─────────────────────────────────────────────────┘ +``` + +**필수 컴포넌트**: +- `v2-table-search-widget` (1개) +- `v2-table-list` (1개) + +**설정 포인트**: +- 테이블명 지정 +- 검색 대상 컬럼 설정 +- 컬럼 표시/숨김 설정 + +--- + +### 3.2 패턴 B: 마스터-디테일 화면 + +**적용 화면**: 공정관리, 견적관리, 수주관리, 품목라우팅 등 + +``` +┌──────────────────┬──────────────────────────────┐ +│ v2-table-list │ v2-table-list 또는 폼 │ +│ (마스터) │ (디테일) │ +│ ─────────────── │ │ +│ □ A001 항목1 │ [상세 정보] │ +│ □ A002 항목2 ← │ │ +│ □ A003 항목3 │ │ +└──────────────────┴──────────────────────────────┘ + v2-split-panel-layout +``` + +**필수 컴포넌트**: +- `v2-split-panel-layout` (1개) +- `v2-table-list` (2개: 마스터, 디테일) + +**설정 포인트**: +- `splitRatio`: 좌우 비율 (기본 30:70) +- `relation.type`: join / detail / custom +- `relation.foreignKey`: 연결 키 컬럼 + +--- + +### 3.3 패턴 C: 마스터-디테일 + 탭 + +**적용 화면**: 거래처관리, 품목정보, 설비정보 등 + +``` +┌──────────────────┬──────────────────────────────┐ +│ v2-table-list │ v2-tabs-widget │ +│ (마스터) │ ┌────┬────┬────┐ │ +│ │ │기본│이력│첨부│ │ +│ □ A001 거래처1 │ └────┴────┴────┘ │ +│ □ A002 거래처2 ← │ [탭별 컨텐츠] │ +└──────────────────┴──────────────────────────────┘ +``` + +**필수 컴포넌트**: +- `v2-split-panel-layout` (1개) +- `v2-table-list` (1개: 마스터) +- `v2-tabs-widget` (1개) + +**설정 포인트**: +- 탭별 표시할 테이블/폼 설정 +- 마스터 선택 시 탭 컨텐츠 연동 + +--- + +### 3.4 패턴 D: 카드 뷰 + +**적용 화면**: 설비정보, 대시보드, 상품 카탈로그 등 + +``` +┌─────────────────────────────────────────────────┐ +│ v2-table-search-widget │ +├─────────────────────────────────────────────────┤ +│ v2-card-display │ +│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ +│ │ [이미지]│ │ [이미지]│ │ [이미지]│ │ +│ │ 제목 │ │ 제목 │ │ 제목 │ │ +│ │ 설명 │ │ 설명 │ │ 설명 │ │ +│ └─────────┘ └─────────┘ └─────────┘ │ +└─────────────────────────────────────────────────┘ +``` + +**필수 컴포넌트**: +- `v2-table-search-widget` (1개) +- `v2-card-display` (1개) + +**설정 포인트**: +- `cardsPerRow`: 한 행당 카드 수 +- `columnMapping`: 제목, 부제목, 이미지, 상태 필드 매핑 +- `cardStyle`: 이미지 위치, 크기 + +--- + +### 3.5 패턴 E: 피벗 분석 + +**적용 화면**: 매출분석, 재고현황, 생산실적 분석 등 + +``` +┌─────────────────────────────────────────────────┐ +│ v2-pivot-grid │ +│ │ 2024년 │ 2025년 │ 2026년 │ 합계 │ +│ ─────────────────────────────────────────────── │ +│ 지역A │ 1,000 │ 1,200 │ 1,500 │ 3,700 │ +│ 지역B │ 2,000 │ 2,500 │ 3,000 │ 7,500 │ +│ 합계 │ 3,000 │ 3,700 │ 4,500 │ 11,200 │ +└─────────────────────────────────────────────────┘ +``` + +**필수 컴포넌트**: +- `v2-pivot-grid` (1개) + +**설정 포인트**: +- `fields[].area`: row / column / data / filter +- `fields[].summaryType`: sum / avg / count / min / max +- `fields[].groupInterval`: 날짜 그룹화 (year/quarter/month) + +--- + +## 4. 회사별 개발 시 핵심 체크포인트 + +### 4.1 테이블 설계 확인 + +**가장 먼저 확인**: +1. 회사에서 사용할 테이블 목록 +2. 테이블 간 관계 (FK) +3. 조회 조건으로 쓸 컬럼 + +``` +✅ 체크리스트: +□ 테이블명이 DB에 존재하는가? +□ company_code 컬럼이 있는가? (멀티테넌시) +□ 마스터-디테일 관계의 FK가 정의되어 있는가? +□ 검색 대상 컬럼에 인덱스가 있는가? +``` + +### 4.2 화면 패턴 판단 + +**질문을 통한 판단**: + +| 질문 | 예 → 패턴 | +|------|----------| +| 단일 테이블만 조회/편집? | 패턴 A (기본 마스터) | +| 마스터 선택 시 디테일 표시? | 패턴 B (마스터-디테일) | +| 상세에 탭이 필요? | 패턴 C (마스터-디테일+탭) | +| 이미지+정보 카드 형태? | 패턴 D (카드 뷰) | +| 다차원 집계/분석? | 패턴 E (피벗) | + +### 4.3 컴포넌트 설정 필수 항목 + +#### v2-table-list 필수 설정 + +```typescript +{ + selectedTable: "테이블명", // 필수 + columns: [ // 표시할 컬럼 + { columnName: "id", displayName: "ID", visible: true, sortable: true }, + // ... + ], + pagination: { + enabled: true, + pageSize: 20 + } +} +``` + +#### v2-split-panel-layout 필수 설정 + +```typescript +{ + leftPanel: { + tableName: "마스터_테이블명" + }, + rightPanel: { + tableName: "디테일_테이블명", + relation: { + type: "detail", // join | detail | custom + foreignKey: "master_id" // 연결 키 + } + }, + splitRatio: 30 // 좌측 비율 +} +``` + +#### v2-card-display 필수 설정 + +```typescript +{ + dataSource: "table", + columnMapping: { + title: "name", // 제목 필드 + subtitle: "code", // 부제목 필드 + image: "image_url", // 이미지 필드 (선택) + status: "status" // 상태 필드 (선택) + }, + cardsPerRow: 3 +} +``` + +--- + +## 5. 공통 컴포넌트 한계점 + +### 5.1 현재 불가능한 기능 + +| 기능 | 상태 | 대안 | +|------|------|------| +| 트리 뷰 (BOM, 조직도) | ❌ 미지원 | 테이블로 대체 or 별도 개발 | +| 그룹화 테이블 | ❌ 미지원 | 일반 테이블로 대체 or 별도 개발 | +| 간트 차트 | ❌ 미지원 | 별도 개발 필요 | +| 드래그앤드롭 정렬 | ❌ 미지원 | 순서 컬럼으로 대체 | +| 인라인 편집 | ⚠️ 제한적 | 모달 편집으로 대체 | +| 복잡한 차트 | ❌ 미지원 | 외부 라이브러리 연동 | + +### 5.2 권장하지 않는 조합 + +| 조합 | 이유 | +|------|------| +| 3단계 이상 중첩 분할 | 화면 복잡도 증가, 성능 저하 | +| 탭 안에 탭 | 사용성 저하 | +| 한 화면에 3개 이상 테이블 | 데이터 로딩 성능 | +| 피벗 + 상세 테이블 동시 | 데이터 과부하 | + +--- + +## 6. 제어관리 (비즈니스 로직) - 별도 설정 필수 + +> **핵심**: V2 컴포넌트는 **UI만 담당**합니다. 비즈니스 로직은 **제어관리**에서 별도 설정해야 합니다. + +### 6.1 UI vs 제어 분리 구조 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 화면 구성 │ +├─────────────────────────────┬───────────────────────────────────┤ +│ UI 레이아웃 │ 제어관리 │ +│ (screen_layouts_v2) │ (dataflow_diagrams) │ +├─────────────────────────────┼───────────────────────────────────┤ +│ • 컴포넌트 배치 │ • 버튼 클릭 시 액션 │ +│ • 검색 필드 구성 │ • INSERT/UPDATE/DELETE 설정 │ +│ • 테이블 컬럼 표시 │ • 조건부 실행 │ +│ • 카드/탭 레이아웃 │ • 다중 행 처리 │ +│ │ • 테이블 간 데이터 이동 │ +└─────────────────────────────┴───────────────────────────────────┘ +``` + +### 6.2 HTML에서 파악 가능/불가능 + +| 구분 | HTML에서 파악 | 이유 | +|------|--------------|------| +| 컴포넌트 배치 | ✅ 가능 | HTML 구조에서 보임 | +| 검색 필드 | ✅ 가능 | input 태그로 확인 | +| 테이블 컬럼 | ✅ 가능 | thead에서 확인 | +| **저장 테이블** | ❌ 불가능 | JS/백엔드에서 처리 | +| **버튼 액션** | ❌ 불가능 | 제어관리에서 설정 | +| **전/후 처리** | ❌ 불가능 | 제어관리에서 설정 | +| **다중 행 처리** | ❌ 불가능 | 제어관리에서 설정 | +| **테이블 간 관계** | ❌ 불가능 | DB/제어관리에서 설정 | + +### 6.3 제어관리 설정 항목 + +#### 트리거 타입 +- **버튼 클릭 전 (before)**: 클릭 직전 실행 +- **버튼 클릭 후 (after)**: 클릭 완료 후 실행 + +#### 액션 타입 +- **INSERT**: 새로운 데이터 삽입 +- **UPDATE**: 기존 데이터 수정 +- **DELETE**: 데이터 삭제 + +#### 조건 설정 +```typescript +// 예: 선택된 행의 상태가 '대기'인 경우에만 실행 +{ + field: "status", + operator: "=", + value: "대기", + dataType: "string" +} +``` + +#### 필드 매핑 +```typescript +// 예: 소스 테이블의 값을 타겟 테이블로 이동 +{ + sourceTable: "order_master", + sourceField: "order_no", + targetTable: "order_history", + targetField: "order_no" +} +``` + +### 6.4 제어관리 예시: 수주 확정 버튼 + +**시나리오**: 수주 목록에서 3건 선택 후 [확정] 버튼 클릭 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ [확정] 버튼 클릭 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. 조건 체크: status = '대기' 인 행만 │ +│ 2. UPDATE order_master SET status = '확정' WHERE id IN (선택) │ +│ 3. INSERT order_history (수주이력 테이블에 기록) │ +│ 4. 외부 시스템 호출 (ERP 연동) │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**제어관리 설정**: +```json +{ + "triggerType": "after", + "actions": [ + { + "actionType": "update", + "targetTable": "order_master", + "conditions": [{ "field": "status", "operator": "=", "value": "대기" }], + "fieldMappings": [{ "targetField": "status", "defaultValue": "확정" }] + }, + { + "actionType": "insert", + "targetTable": "order_history", + "fieldMappings": [ + { "sourceField": "order_no", "targetField": "order_no" }, + { "sourceField": "customer_name", "targetField": "customer_name" } + ] + } + ] +} +``` + +### 6.5 회사별 개발 시 제어관리 체크리스트 + +``` +□ 버튼별 액션 정의 + - 어떤 버튼이 있는가? + - 각 버튼 클릭 시 무슨 동작? + +□ 저장/수정/삭제 대상 테이블 + - 메인 테이블은? + - 이력 테이블은? + - 연관 테이블은? + +□ 조건부 실행 + - 특정 상태일 때만 실행? + - 특정 값 체크 필요? + +□ 다중 행 처리 + - 여러 행 선택 후 일괄 처리? + - 각 행별 개별 처리? + +□ 외부 연동 + - ERP/MES 등 외부 시스템 호출? + - API 연동 필요? +``` + +--- + +## 7. 회사별 커스터마이징 영역 + +### 7.1 컴포넌트로 처리되는 영역 (표준화) + +| 영역 | 설명 | +|------|------| +| UI 레이아웃 | 컴포넌트 배치, 크기, 위치 | +| 검색 조건 | 화면 디자이너에서 설정 | +| 테이블 컬럼 | 표시/숨김, 순서, 너비 | +| 기본 CRUD | 조회, 저장, 삭제 자동 처리 | +| 페이지네이션 | 자동 처리 | +| 정렬/필터 | 자동 처리 | + +### 7.2 회사별 개발 필요 영역 + +| 영역 | 설명 | 개발 방법 | +|------|------|----------| +| 비즈니스 로직 | 저장 전/후 검증, 계산 | 데이터플로우 또는 백엔드 API | +| 특수 UI | 간트, 트리, 차트 등 | 별도 컴포넌트 개발 | +| 외부 연동 | ERP, MES 등 연계 | 외부 호출 설정 | +| 리포트/인쇄 | 전표, 라벨 출력 | 리포트 컴포넌트 | +| 결재 프로세스 | 승인/반려 흐름 | 워크플로우 설정 | + +--- + +## 8. 빠른 개발 가이드 + +### Step 1: 화면 분석 +1. 어떤 테이블을 사용하는가? +2. 테이블 간 관계는? +3. 어떤 패턴인가? (A/B/C/D/E) + +### Step 2: 컴포넌트 배치 +1. 화면 디자이너에서 패턴에 맞는 컴포넌트 배치 +2. 각 컴포넌트에 테이블/컬럼 설정 + +### Step 3: 연동 설정 +1. 마스터-디테일 관계 설정 (FK) +2. 검색 조건 설정 +3. 버튼 액션 설정 + +### Step 4: 테스트 +1. 데이터 조회 확인 +2. 마스터 선택 시 디테일 연동 확인 +3. 저장/삭제 동작 확인 + +--- + +## 9. 요약 + +### V2 컴포넌트 커버리지 + +| 화면 유형 | 지원 여부 | 주요 컴포넌트 | +|-----------|----------|--------------| +| 기본 CRUD | ✅ 완전 | v2-table-list, v2-table-search-widget | +| 마스터-디테일 | ✅ 완전 | v2-split-panel-layout | +| 탭 화면 | ✅ 완전 | v2-tabs-widget | +| 카드 뷰 | ✅ 완전 | v2-card-display | +| 피벗 분석 | ✅ 완전 | v2-pivot-grid | +| 그룹화 테이블 | ❌ 미지원 | 개발 필요 | +| 트리 뷰 | ❌ 미지원 | 개발 필요 | +| 간트 차트 | ❌ 미지원 | 개발 필요 | + +### 개발 시 핵심 원칙 + +1. **테이블 먼저**: DB 테이블 구조 확인이 최우선 +2. **패턴 판단**: 5가지 패턴 중 어디에 해당하는지 판단 +3. **표준 조합**: 검증된 컴포넌트 조합 사용 +4. **한계 인식**: 불가능한 UI는 조기에 식별하여 별도 개발 계획 +5. **멀티테넌시**: 모든 테이블에 company_code 필터링 필수 +6. **제어관리 필수**: UI 완성 후 버튼별 비즈니스 로직 설정 필수 + +### UI vs 제어 구분 + +| 영역 | 담당 | 설정 위치 | +|------|------|----------| +| 화면 레이아웃 | V2 컴포넌트 | 화면 디자이너 | +| 비즈니스 로직 | 제어관리 | dataflow_diagrams | +| 외부 연동 | 외부호출 설정 | external_call_configs | + +**HTML에서 배낄 수 있는 것**: UI 구조만 +**별도 설정 필요한 것**: 저장 테이블, 버튼 액션, 조건 처리, 다중 행 처리 diff --git a/docs/screen-implementation-guide/01_master-data/bom.md b/docs/screen-implementation-guide/01_master-data/bom.md new file mode 100644 index 00000000..6e626289 --- /dev/null +++ b/docs/screen-implementation-guide/01_master-data/bom.md @@ -0,0 +1,255 @@ +# BOM관리 화면 구현 가이드 + +> **화면명**: BOM관리 +> **파일**: BOM관리.html +> **분류**: 기준정보 +> **구현 가능**: ⚠️ 부분 (트리 뷰 컴포넌트 필요) + +--- + +## 1. 화면 개요 + +BOM(Bill of Materials) 관리 화면으로, 제품의 부품 구성을 트리 구조로 관리합니다. + +### 핵심 기능 +- BOM 목록 조회/검색 +- BOM 구조 트리 표시 (정전개/역전개) +- BOM 등록/수정/삭제 +- 버전/차수 관리 +- 엑셀 업로드/다운로드 + +--- + +## 2. 화면 레이아웃 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ [품목코드] [품목명] [품목구분▼] [버전▼] [사용여부▼] [초기화][조회]│ +│ [사용자옵션][업로드][다운로드]│ +├───────────────────────┬─────────────────────────────────────────┤ +│ 📦 BOM 목록 │ 📋 BOM 상세정보 │ +│ ─────────────── │ [이력] [버전] [수정] [삭제] │ +│ [신규등록] │ ───────────────────────── │ +│ ┌──────────────────┐ │ 품목코드: PRD-001 │ +│ │□|코드|품목명|구분..│ │ 품목명: 제품A │ +│ │□|P01|제품A |제품 │ │ 기준수량: 1 │ +│ │□|P02|제품B |제품 │ ├─────────────────────────────────────────┤ +│ └──────────────────┘ │ 🌳 BOM 구조 │ +│ │ 기준수량:[1] [트리|레벨] [정전개|역전개] │ +│ 리사이저 ↔ │ ───────────────────────── │ +│ │ ▼ PRD-001 제품A (1.00 EA) │ +│ │ ├─ MAT-001 원자재A (2.00 KG) │ +│ │ └─ SEM-001 반제품A (1.00 EA) │ +│ │ └─ MAT-002 원자재B (0.50 KG) │ +└───────────────────────┴─────────────────────────────────────────┘ +``` + +--- + +## 3. V2 컴포넌트 매핑 + +### 3.1 구현 가능 영역 + +| HTML 영역 | V2 컴포넌트 | 상태 | +|-----------|-------------|------| +| 검색 섹션 | `v2-table-search-widget` | ✅ 가능 | +| BOM 목록 테이블 | `v2-table-list` | ✅ 가능 | +| 분할 패널 | `v2-split-panel-layout` | ⚠️ 부분 | + +### 3.2 신규 컴포넌트 필요 + +| HTML 영역 | 필요 컴포넌트 | 재활용 가능성 | +|-----------|---------------|--------------| +| BOM 트리 구조 | `v2-tree-view` | 3개 화면 (부서정보, 메뉴관리) | +| BOM 등록 모달 | `v2-modal-form` | 모든 화면 | + +--- + +## 4. 테이블 정의 + +### 4.1 BOM 목록 테이블 (좌측) + +```typescript +columns: [ + { id: 'checkbox', type: 'checkbox', width: 50 }, + { id: 'item_code', label: '품목코드', width: 100 }, + { id: 'item_name', label: '품목명', width: 150 }, + { id: 'item_type', label: '품목구분', width: 80 }, + { id: 'version', label: '버전', width: 70 }, + { id: 'revision', label: '차수', width: 70 }, + { id: 'status', label: '사용여부', width: 80 }, + { id: 'reg_date', label: '등록일', width: 100 } +] +``` + +### 4.2 BOM 상세 필드 + +```typescript +detailFields: [ + { id: 'item_code', label: '품목코드' }, + { id: 'item_name', label: '품목명' }, + { id: 'item_type', label: '품목구분' }, + { id: 'unit', label: '단위' }, + { id: 'base_qty', label: '기준수량' }, + { id: 'version', label: '버전' }, + { id: 'revision', label: '차수' }, + { id: 'status', label: '사용여부' }, + { id: 'remark', label: '비고' } +] +``` + +--- + +## 5. 검색 조건 + +| 필드명 | 컴포넌트 | 옵션 | +|--------|----------|------| +| 품목코드 | `v2-input` | placeholder: "품목코드" | +| 품목명 | `v2-input` | placeholder: "품목명" | +| 품목구분 | `v2-select` | 제품, 반제품, 원자재 | +| 버전 | `v2-select` | 1.0, 2.0, 3.0 | +| 사용여부 | `v2-select` | 사용, 미사용 | + +--- + +## 6. 특수 기능: BOM 트리 (신규 컴포넌트 필요) + +### 6.1 트리 노드 구조 + +```typescript +interface BomTreeNode { + id: string; + itemCode: string; + itemName: string; + itemType: string; + quantity: number; + unit: string; + level: number; + children: BomTreeNode[]; + expanded: boolean; +} +``` + +### 6.2 정전개 vs 역전개 + +| 모드 | 설명 | +|------|------| +| 정전개 (Forward) | 선택 품목 → 하위 구성품목 표시 | +| 역전개 (Reverse) | 선택 품목 → 상위 사용처 표시 | + +### 6.3 필요 인터랙션 + +- 노드 클릭: 펼치기/접기 +- 전체 펼치기/접기 버튼 +- 레벨 뷰/트리 뷰 전환 +- 기준수량 변경 시 수량 재계산 + +--- + +## 7. 모달 폼 정의 + +### 7.1 BOM 등록 모달 + +```typescript +modalFields: [ + { id: 'item_code', label: '품목코드', type: 'autocomplete', required: true }, + { id: 'item_name', label: '품목명', type: 'autocomplete', required: true }, + { id: 'item_type', label: '품목구분', type: 'select', required: true }, + { id: 'unit', label: '단위', type: 'select', required: true }, + { id: 'base_qty', label: '기준수량', type: 'number', required: true }, + { id: 'version', label: '버전', type: 'text', readonly: true }, + { id: 'revision', label: '차수', type: 'text', readonly: true }, + { id: 'status', label: '사용여부', type: 'radio', options: ['사용', '미사용'] }, + { id: 'remark', label: '비고', type: 'textarea' } +] + +// 하위 품목 섹션 +childItemsSection: { + title: '하위 품목 구성', + addButton: '품목추가', + columns: [ + { id: 'item_code', label: '품목코드' }, + { id: 'item_name', label: '품목명' }, + { id: 'quantity', label: '소요량' }, + { id: 'unit', label: '단위' }, + { id: 'loss_rate', label: '로스율(%)' }, + { id: 'actions', label: '' } + ] +} +``` + +--- + +## 8. 현재 구현 가능 범위 + +### ✅ 가능 +- 검색 영역 (v2-table-search-widget) +- BOM 목록 테이블 (v2-table-list) +- 분할 패널 레이아웃 (v2-split-panel-layout) +- 기본 상세 정보 표시 + +### ⚠️ 부분 가능 (대체 구현) +- BOM 구조: 트리 대신 레벨 테이블로 표시 가능 + +### ❌ 불가능 (신규 개발 필요) +- 진정한 트리 뷰 (접기/펼치기) +- 정전개/역전개 전환 +- 하위 품목 동적 추가 모달 + +--- + +## 9. 간소화 구현 JSON + +```json +{ + "screen_code": "BOM_MAIN", + "screen_name": "BOM관리", + "components": [ + { + "type": "v2-table-search-widget", + "config": { + "searchFields": [ + { "type": "input", "id": "item_code", "placeholder": "품목코드" }, + { "type": "input", "id": "item_name", "placeholder": "품목명" }, + { "type": "select", "id": "item_type", "placeholder": "품목구분" }, + { "type": "select", "id": "status", "placeholder": "사용여부" } + ], + "buttons": [ + { "label": "초기화", "action": "reset" }, + { "label": "조회", "action": "search", "variant": "primary" } + ] + } + }, + { + "type": "v2-split-panel-layout", + "config": { + "masterPanel": { + "title": "BOM 목록", + "entityId": "bom_header", + "columns": [ + { "id": "item_code", "label": "품목코드", "width": 100 }, + { "id": "item_name", "label": "품목명", "width": 150 }, + { "id": "item_type", "label": "품목구분", "width": 80 }, + { "id": "version", "label": "버전", "width": 70 } + ] + }, + "detailPanel": { + "title": "BOM 상세정보", + "entityId": "bom_detail", + "relationType": "one-to-many" + } + } + } + ] +} +``` + +--- + +## 10. 개발 권장사항 + +1. **1단계**: 현재 컴포넌트로 기본 CRUD 구현 +2. **2단계**: `v2-tree-view` 개발 후 BOM 구조 통합 +3. **3단계**: 버전/차수 관리 기능 추가 + +**예상 재활용**: `v2-tree-view`는 부서정보, 메뉴관리에서도 사용 가능 (3개 화면) diff --git a/docs/screen-implementation-guide/02_sales/customer.md b/docs/screen-implementation-guide/02_sales/customer.md new file mode 100644 index 00000000..7699f798 --- /dev/null +++ b/docs/screen-implementation-guide/02_sales/customer.md @@ -0,0 +1,256 @@ +# 거래처관리 화면 구현 가이드 + +> **화면명**: 거래처관리 +> **파일**: 거래처관리.html +> **분류**: 영업관리 +> **구현 가능**: ⚠️ 부분 (그룹화 테이블 필요) + +--- + +## 1. 화면 개요 + +고객사 및 공급업체 정보를 통합 관리하는 화면입니다. + +### 핵심 기능 +- 거래처 목록 조회/검색 +- 그룹화 기능 (거래처유형, 지역별) +- 거래처 등록/수정/삭제 +- 거래처별 품목코드/단가 관리 +- 담당자 정보 관리 + +--- + +## 2. 화면 레이아웃 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ [거래처코드] [거래처명] [거래처유형▼] [사용여부▼] [초기화][조회] │ +│ [사용자옵션][업로드][다운로드]│ +├───────────────────────┬─────────────────────────────────────────┤ +│ 📋 거래처 목록 │ [기본정보][품목코드][단가정보][담당자] │ +│ ───────────────── │ ───────────────────────────────────── │ +│ Group by: [거래처유형▼] │ 거래처코드: C-001 │ +│ ┌──────────────────┐ │ 거래처명: (주)테스트 │ +│ │▼ 고객사 (15) │ │ 사업자번호: 123-45-67890 │ +│ │ C-001 | A사 │ │ 대표자: 홍길동 │ +│ │ C-002 | B사 │ ├─────────────────────────────────────────┤ +│ │▼ 공급업체 (8) │ │ [품목코드 탭 내용] │ +│ │ S-001 | 원자재사 │ │ ┌────────────────────────────────┐ │ +│ └──────────────────┘ │ │거래처품목코드|품목명|자사품목코드│ │ +│ │ │CP-001 |원료A |M-001 │ │ +│ 리사이저 ↔ │ └────────────────────────────────┘ │ +└───────────────────────┴─────────────────────────────────────────┘ +``` + +--- + +## 3. V2 컴포넌트 매핑 + +| HTML 영역 | V2 컴포넌트 | 상태 | +|-----------|-------------|------| +| 검색 섹션 | `v2-table-search-widget` | ✅ 가능 | +| 거래처 목록 (그룹화) | `v2-table-list` | ⚠️ 그룹화 미지원 | +| 분할 패널 | `v2-split-panel-layout` | ✅ 가능 | +| 상세 탭 | `v2-tabs-widget` | ✅ 가능 | + +--- + +## 4. 테이블 정의 + +### 4.1 거래처 목록 + +```typescript +columns: [ + { id: 'checkbox', type: 'checkbox', width: 50 }, + { id: 'customer_code', label: '거래처코드', width: 100 }, + { id: 'customer_name', label: '거래처명', width: 200 }, + { id: 'customer_type', label: '거래처유형', width: 100 }, + { id: 'business_no', label: '사업자번호', width: 120 }, + { id: 'ceo_name', label: '대표자', width: 100 }, + { id: 'tel', label: '전화번호', width: 120 }, + { id: 'status', label: '사용여부', width: 80 } +] +``` + +### 4.2 품목코드 탭 + +```typescript +itemCodeColumns: [ + { id: 'customer_item_code', label: '거래처품목코드', width: 150 }, + { id: 'item_name', label: '품목명', width: 200 }, + { id: 'our_item_code', label: '자사품목코드', width: 150 }, + { id: 'spec', label: '규격', width: 150 } +] +``` + +### 4.3 단가정보 탭 + +```typescript +priceColumns: [ + { id: 'item_code', label: '품목코드', width: 120 }, + { id: 'item_name', label: '품목명', width: 200 }, + { id: 'unit_price', label: '단가', width: 100, format: 'currency' }, + { id: 'currency', label: '통화', width: 60 }, + { id: 'apply_date', label: '적용일', width: 100 }, + { id: 'remark', label: '비고', width: 150 } +] +``` + +--- + +## 5. 그룹화 기능 (신규 컴포넌트 필요) + +### 5.1 그룹화 옵션 + +```typescript +groupByOptions: [ + { id: 'customer_type', label: '거래처유형' }, + { id: 'region', label: '지역' }, + { id: 'status', label: '사용여부' } +] +``` + +### 5.2 그룹 헤더 표시 + +``` +▼ 고객사 (15) ← 그룹명 + 건수 + │ C-001 │ (주)A사 │ ... + │ C-002 │ (주)B사 │ ... +▼ 공급업체 (8) + │ S-001 │ 원자재사 │ ... +``` + +### 5.3 필요 인터랙션 + +- 그룹 접기/펼치기 +- 그룹 전체 선택 체크박스 +- 다중 그룹핑 (선택) + +--- + +## 6. 탭 구성 + +```typescript +tabs: [ + { + id: 'basic', + label: '기본정보', + fields: [ + { id: 'customer_code', label: '거래처코드' }, + { id: 'customer_name', label: '거래처명' }, + { id: 'customer_type', label: '거래처유형' }, + { id: 'business_no', label: '사업자번호' }, + { id: 'ceo_name', label: '대표자' }, + { id: 'address', label: '주소' }, + { id: 'tel', label: '전화번호' }, + { id: 'fax', label: '팩스' }, + { id: 'email', label: '이메일' } + ] + }, + { + id: 'item_codes', + label: '품목코드', + type: 'table', + entityId: 'customer_item_mapping' + }, + { + id: 'prices', + label: '단가정보', + type: 'table', + entityId: 'customer_prices' + }, + { + id: 'contacts', + label: '담당자', + type: 'table', + entityId: 'customer_contacts' + } +] +``` + +--- + +## 7. 현재 구현 가능 범위 + +### ✅ 가능 +- 검색 영역 +- 분할 패널 레이아웃 +- 상세 탭 +- 품목코드/단가/담당자 테이블 + +### ⚠️ 부분 가능 +- 거래처 목록: 그룹화 없이 일반 테이블로 구현 + +### ❌ 불가능 +- 동적 그룹화 (그룹 접기/펼치기) + +--- + +## 8. 간소화 구현 JSON (그룹화 제외) + +```json +{ + "screen_code": "CUSTOMER_MAIN", + "screen_name": "거래처관리", + "components": [ + { + "type": "v2-table-search-widget", + "config": { + "searchFields": [ + { "type": "input", "id": "customer_code", "placeholder": "거래처코드" }, + { "type": "input", "id": "customer_name", "placeholder": "거래처명" }, + { "type": "select", "id": "customer_type", "placeholder": "거래처유형", + "options": [ + { "value": "customer", "label": "고객사" }, + { "value": "supplier", "label": "공급업체" }, + { "value": "both", "label": "고객사/공급업체" } + ] + }, + { "type": "select", "id": "status", "placeholder": "사용여부" } + ] + } + }, + { + "type": "v2-split-panel-layout", + "config": { + "masterPanel": { + "title": "거래처 목록", + "entityId": "customer_master", + "columns": [ + { "id": "customer_code", "label": "거래처코드", "width": 100 }, + { "id": "customer_name", "label": "거래처명", "width": 200 }, + { "id": "customer_type", "label": "거래처유형", "width": 100 }, + { "id": "ceo_name", "label": "대표자", "width": 100 } + ] + }, + "detailPanel": { + "tabs": [ + { "id": "basic", "label": "기본정보", "type": "form" }, + { "id": "items", "label": "품목코드", "type": "table", "entityId": "customer_items" }, + { "id": "prices", "label": "단가정보", "type": "table", "entityId": "customer_prices" }, + { "id": "contacts", "label": "담당자", "type": "table", "entityId": "customer_contacts" } + ] + } + } + } + ] +} +``` + +--- + +## 9. v2-grouped-table 개발 시 추가 구현 + +```typescript +// 그룹화 테이블 설정 +groupedTableConfig: { + groupBy: 'customer_type', + groupByOptions: ['customer_type', 'region', 'status'], + showGroupCount: true, + expandAll: false, + groupCheckbox: true +} +``` + +**예상 재활용**: `v2-grouped-table`은 5개 이상 화면에서 사용 가능 +- 거래처관리, 품목정보, 작업지시, 입출고관리, 견적관리 diff --git a/docs/screen-implementation-guide/02_sales/order.md b/docs/screen-implementation-guide/02_sales/order.md new file mode 100644 index 00000000..ff302b67 --- /dev/null +++ b/docs/screen-implementation-guide/02_sales/order.md @@ -0,0 +1,1276 @@ +# 수주관리 (Sales Order Management) + +> Screen ID: /screens/156 +> 메뉴 경로: 영업관리 > 수주관리 +> 테이블: `sales_order_mng` + +--- + +## ⚠️ 문서 사용 안내 + +> **이 문서는 "수주관리" 화면의 구현 예시입니다.** +> +> ### 📌 중요: JSON 데이터는 참고용입니다! +> +> 이 문서에 포함된 JSON 설정(레이아웃, 컴포넌트 구성 등)은 **수주관리 화면에 특화된 예시**입니다. +> +> **다른 화면을 구현할 때:** +> 1. 이 JSON을 그대로 복사해서 사용하지 마세요 +> 2. 해당 화면의 **테이블 구조를 먼저 분석**하세요 +> 3. 화면의 **요구사항과 기능을 파악**하세요 +> 4. 분석 결과에 맞는 **새로운 JSON 구조를 작성**하세요 + +--- + +## 1. 테이블 선택 및 화면 구조 + +### 1.1 사용 테이블 + +| 테이블명 | 용도 | 비고 | +|----------|------|------| +| `sales_order_mng` | 수주 마스터 데이터 | 주 테이블 | +| `customer_mng` | 거래처 정보 | FK: partner_id | +| `item_info` | 품목 정보 | FK: part_code | + +### 1.2 테이블 컬럼 정의 (실제 DB 기준) + +| 컬럼명 | 표시명 | 타입 | 필수 | 설명 | +|--------|--------|------|------|------| +| `id` | ID | integer | PK | 자동 생성 (시퀀스) | +| `company_code` | 회사코드 | varchar | ✅ | 멀티테넌시 | +| `order_no` | 수주번호 | varchar | ✅ | 수주 고유 코드 | +| `order_date` | 수주일 | date | | 수주 등록일 | +| `due_date` | 납기일 | date | | 납품 예정일 | +| `partner_id` | 거래처ID | varchar | | 거래처 코드 (FK) | +| `delivery_partner_id` | 납품처ID | varchar | | 납품처 코드 | +| `delivery_address` | 납품장소 | text | | 납품 주소 | +| `shipping_method` | 배송방법 | varchar | | 택배, 화물, 직송 등 | +| `part_code` | 품목코드 | varchar | | 품목 코드 (FK) | +| `part_name` | 품명 | varchar | | 품목명 | +| `spec` | 규격 | varchar | | 규격 정보 | +| `material` | 재질 | varchar | | 재질 정보 | +| `order_qty` | 수주수량 | numeric | | 기본값 0 | +| `ship_qty` | 출하수량 | numeric | | 기본값 0 | +| `balance_qty` | 잔량 | numeric | | 기본값 0 (수주수량 - 출하수량) | +| `inventory_qty` | 현재고 | numeric | | 기본값 0 | +| `plan_ship_qty` | 출하계획량 | numeric | | 기본값 0 | +| `unit_price` | 단가 | numeric | | 기본값 0 | +| `total_amount` | 금액 | numeric | | 기본값 0 (수주수량 × 단가) | +| `status` | 상태 | varchar | | 수주, 진행중, 완료, 취소 (기본값: 수주) | +| `manager_id` | 담당자ID | varchar | | 담당자 ID | +| `manager_name` | 담당자명 | varchar | | 담당자 이름 | +| `memo` | 메모 | text | | 비고 | +| `sales_type` | 영업유형 | varchar | | 내수, 수출 등 | +| `part_name_eng` | 품명(영문) | varchar | | 영문 품목명 | +| `item_due_date` | 품목납기일 | varchar | | 품목별 납기일 | +| `incoterms` | 인코텀즈 | varchar | | 무역조건 (수출용) | +| `payment_term` | 결제조건 | varchar | | 결제 조건 | +| `port_of_loading` | 선적항 | varchar | | 선적 항구 (수출용) | +| `port_of_discharge` | 도착항 | varchar | | 도착 항구 (수출용) | +| `hs_code` | HS코드 | varchar | | 관세 코드 (수출용) | +| `currency` | 통화 | varchar | | 통화 코드 | +| `created_date` | 등록일 | timestamp | | 자동 생성 | +| `created_by` | 등록자 | varchar | | 등록자 ID | +| `updated_date` | 수정일 | timestamp | | 자동 갱신 | +| `updated_by` | 수정자 | varchar | | 수정자 ID | +| `writer` | 작성자 | varchar | | 작성자 ID | + +### 1.3 화면 구조 개요 + +- **화면 유형**: 목록형 (단일 테이블 CRUD) +- **주요 기능**: + - 수주 조회/검색/필터링 + - 수주 등록/수정/삭제 + - 그룹핑 (Group By) + - 출하계획 연동 + - 엑셀 업로드/다운로드 + - 통계 표시 (총 금액, 총 수량) + +--- + +## 2. 컴포넌트 배치도 + +### 2.1 전체 레이아웃 + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ [검색 영역] │ +│ ┌─────────────────────────────────────────────────────────────────────────┐ │ +│ │ v2-table-search-widget │ │ +│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │ +│ │ │ 수주번호 │ │ 거래처 │ │ 품목명 │ │ 상태 │ │ 수주일 │ │ │ +│ │ │ (text) │ │ (select) │ │ (text) │ │ (select) │ │ (date) │ │ │ +│ │ └───────────┘ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │ │ +│ │ ┌─────────┐ ┌──────────┐ ┌──────┐ │ │ +│ │ │ 사용자 │ │ 엑셀 │ │엑셀 │ │ │ +│ │ │ 옵션 │ │ 업로드 │ │다운 │ │ │ +│ │ └─────────┘ └──────────┘ └──────┘ │ │ +│ └─────────────────────────────────────────────────────────────────────────┘ │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ [테이블 헤더 + 액션 버튼 + 통계] │ +│ ┌─────────────────────────────────────────────────────────────────────────┐ │ +│ │ 📋 수주 목록 (10) 총 금액: 1,234,000원 총 수량: 5,000개 [Group by ▼]│ │ +│ │ [수주등록][수정][삭제][출하계획] │ │ +│ └─────────────────────────────────────────────────────────────────────────┘ │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ [데이터 테이블] │ +│ ┌─────────────────────────────────────────────────────────────────────────┐ │ +│ │ v2-table-list │ │ +│ │ ┌──┬────────┬────────┬────────┬────────┬──────┬──────┬──────┬────────┐ │ │ +│ │ │☐ │수주번호│거래처 │품목코드│품명 │규격 │재질 │단위 │수주수량│ │ │ +│ │ ├──┼────────┼────────┼────────┼────────┼──────┼──────┼──────┼────────┤ │ │ +│ │ │☐ │ORD-001 │삼성전자│ITEM001 │볼트 M8 │M8x20 │SUS304│EA │1,000 │ │ │ +│ │ │☐ │ORD-002 │LG전자 │ITEM002 │너트 M8 │M8 │SUS304│EA │2,000 │ │ │ +│ │ └──┴────────┴────────┴────────┴────────┴──────┴──────┴──────┴────────┘ │ │ +│ │ (수평 스크롤: 출하수량, 잔량, 현재고, 출하계획량, 단가, 금액, 납품처, │ │ +│ │ 납품장소, 배송방법, 납기일, 수주일, 상태, 담당자, 메모) │ │ +│ └─────────────────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +### 2.2 사용 가능한 V2 컴포넌트 목록 + +> 📌 **V2 컴포넌트 전체 목록** - 화면 구성 시 사용 가능한 컴포넌트 + +| 컴포넌트 ID | 설명 | 카테고리 | +|-------------|------|----------| +| `v2-input` | 텍스트, 숫자, 비밀번호, 이메일 등 입력 | 입력 | +| `v2-select` | 드롭다운, 콤보박스, 라디오, 체크박스 | 입력 | +| `v2-date` | 날짜/시간 입력 | 입력 | +| `v2-button-primary` | 버튼 | 액션 | +| `v2-table-list` | 테이블 리스트 (CRUD) | 테이블 | +| `v2-table-search-widget` | 테이블 검색/필터 위젯 | 유틸리티 | +| `v2-aggregation-widget` | 집계 위젯 | 위젯 | +| `v2-text-display` | 텍스트 표시 (읽기 전용) | 표시 | + +### 2.3 이 화면에서 사용하는 컴포넌트 + +| 컴포넌트 타입 | 역할 | +|---------------|------| +| `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` | 출하계획 | +| `v2-aggregation-widget` | 통계 표시 (총 금액, 총 수량) | +| `v2-input` | 모달 - 텍스트 입력 필드 | +| `v2-select` | 모달 - 선택 필드 | +| `v2-date` | 모달 - 날짜 입력 필드 | + +--- + +## 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: 데이터 소스 설정 + +| 설정 항목 | 설정 값 | +|-----------|---------| +| 테이블 선택 | `sales_order_mng` | +| 자동 컬럼 생성 | ✅ 체크 (테이블 컬럼 자동 로드) | + +#### Step 3: 컬럼 설정 + +**[컬럼 설정]** 패널에서 표시할 컬럼 선택 및 순서 조정: + +| 순서 | 컬럼 | 표시명 | 너비 | 정렬 | 표시 | 특수 설정 | +|------|------|--------|------|------|------|-----------| +| 1 | `order_no` | 수주번호 | 130 | 좌측 | ✅ | 굵게 표시 | +| 2 | `partner_id` | 거래처 | 150 | 좌측 | ✅ | 조인: customer_mng.name | +| 3 | `part_code` | 품목코드 | 130 | 좌측 | ✅ | | +| 4 | `part_name` | 품명 | 180 | 좌측 | ✅ | | +| 5 | `spec` | 규격 | 120 | 좌측 | ✅ | | +| 6 | `material` | 재질 | 100 | 좌측 | ✅ | | +| 7 | `unit` | 단위 | 80 | 중앙 | ✅ | 기본값: EA | +| 8 | `order_qty` | 수주수량 | 100 | 우측 | ✅ | 숫자 포맷 | +| 9 | `ship_qty` | 출하수량 | 100 | 우측 | ✅ | 숫자 포맷 | +| 10 | `balance_qty` | 잔량 | 100 | 우측 | ✅ | 숫자 포맷, 굵게 | +| 11 | `inventory_qty` | 현재고 | 100 | 우측 | ✅ | 숫자 포맷 | +| 12 | `plan_ship_qty` | 출하계획량 | 100 | 우측 | ✅ | 숫자 포맷 | +| 13 | `unit_price` | 단가 | 120 | 우측 | ✅ | 숫자 포맷 | +| 14 | `total_amount` | 금액 | 140 | 우측 | ✅ | 숫자 포맷, 굵게 | +| 15 | `delivery_partner_id` | 납품처 | 150 | 좌측 | ✅ | | +| 16 | `delivery_address` | 납품장소 | 150 | 좌측 | ✅ | | +| 17 | `shipping_method` | 배송방법 | 120 | 중앙 | ✅ | | +| 18 | `due_date` | 납기일 | 120 | 중앙 | ✅ | 날짜 포맷 | +| 19 | `order_date` | 수주일 | 120 | 중앙 | ✅ | 날짜 포맷 | +| 20 | `status` | 상태 | 100 | 중앙 | ✅ | 뱃지 스타일 | +| 21 | `manager_name` | 담당자 | 100 | 좌측 | ✅ | | +| 22 | `memo` | 메모 | 200 | 좌측 | ✅ | | + +#### Step 4: 기능 설정 + +| 설정 항목 | 설정 값 | 설명 | +|-----------|---------|------| +| 체크박스 | ✅ 사용 | 다중 선택 활성화 | +| 페이지네이션 | ✅ 사용 | | +| 페이지 크기 | 20 | 기본 표시 행 수 | +| 정렬 | ✅ 사용 | 컬럼 헤더 클릭 정렬 | +| 컬럼 리사이즈 | ✅ 사용 | 컬럼 너비 조정 | +| 그룹핑 | ✅ 사용 | Group By 기능 | +| 수평 스크롤 | ✅ 사용 | 컬럼 수가 많으므로 필수 | + +#### Step 5: 그룹핑 옵션 설정 + +Group By 드롭다운에 표시할 컬럼 선택: +- ✅ `partner_id` (거래처) +- ✅ `status` (상태) +- ✅ `part_name` (품목명) +- ✅ `material` (재질) + +--- + +### 3.3 버튼 설정 + +#### 검색 영역 우측 버튼 + +##### 사용자옵션 버튼 + +| 설정 항목 | 설정 값 | +|-----------|---------| +| 라벨 | `사용자옵션` | +| 아이콘 | ⚙️ | +| 액션 타입 | `custom` | +| 스타일 | `secondary` | +| 동작 | 사용자 옵션 모달 열기 | + +##### 엑셀 업로드 버튼 + +| 설정 항목 | 설정 값 | +|-----------|---------| +| 라벨 | `엑셀 업로드` | +| 아이콘 | 📥 | +| 액션 타입 | `excel_upload` | +| 스타일 | `secondary` | +| 대상 테이블 | `sales_order_mng` | + +##### 엑셀 다운로드 버튼 + +| 설정 항목 | 설정 값 | +|-----------|---------| +| 라벨 | `엑셀 다운로드` | +| 아이콘 | 📤 | +| 액션 타입 | `excel_download` | +| 스타일 | `secondary` | +| 대상 | 현재 테이블 리스트 | + +#### 테이블 헤더 우측 버튼 + +##### 수주등록 버튼 + +| 설정 항목 | 설정 값 | +|-----------|---------| +| 라벨 | `수주 등록` | +| 아이콘 | ➕ | +| 액션 타입 | `modal` | +| 스타일 | `success` | +| 연결 화면 | 수주 등록/수정 화면 (아래 3.4 참조) | +| 모달 제목 | 수주 등록 | +| 모달 사이즈 | `lg` | + +##### 수정 버튼 + +| 설정 항목 | 설정 값 | +|-----------|---------| +| 라벨 | `수정` | +| 아이콘 | ✏️ | +| 액션 타입 | `edit` | +| 스타일 | `secondary` | +| 선택 필수 | ✅ 체크 (1개만) | +| 연결 화면 | 수주 등록/수정 화면 (아래 3.4 참조) | + +##### 삭제 버튼 + +| 설정 항목 | 설정 값 | +|-----------|---------| +| 라벨 | `삭제` | +| 아이콘 | 🗑️ | +| 액션 타입 | `delete` | +| 스타일 | `secondary` | +| 선택 필수 | ✅ 체크 (복수 선택 가능) | +| 확인 메시지 | 선택한 수주를 삭제하시겠습니까? | + +##### 출하계획 버튼 + +| 설정 항목 | 설정 값 | +|-----------|---------| +| 라벨 | `출하계획` | +| 아이콘 | 🚚 | +| 액션 타입 | `custom` | +| 스타일 | `secondary` | +| 선택 필수 | ✅ 체크 (복수 선택 가능) | +| 동작 | 출하계획 슬라이드 패널 열기 | + +--- + +### 3.4 수주 등록/수정 화면 (모달용 화면) + +> 📌 **별도 화면 생성 필요**: 수주등록/수정 버튼에 연결할 모달 화면을 새로 생성합니다. + +#### Step 1: 새 화면 생성 + +1. 화면 관리에서 **[+ 새 화면]** 클릭 +2. 화면 정보 입력: + - 화면명: `수주 등록/수정` + - 테이블: `sales_order_mng` + - 화면 유형: `모달` + +#### Step 2: 폼 필드 배치 + +**모달 레이아웃 배치도**: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 수주 등록/수정 [✕] │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ 수주번호 * │ │ 수주일 * │ │ +│ │ [____________________] │ │ [____________________] │ │ +│ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ 거래처 * │ │ 품목코드 * │ │ +│ │ [삼성전자 ▼] │ │ [____________________] │ │ +│ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ 품명 │ │ 규격 │ │ +│ │ [____________________] │ │ [____________________] │ │ +│ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ 재질 │ │ 단위 │ │ +│ │ [____________________] │ │ [EA ▼] │ │ +│ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ 수주수량 * │ │ 단가 * │ │ +│ │ [____________________] │ │ [____________________] │ │ +│ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ 납기일 │ │ 상태 * │ │ +│ │ [____________________] │ │ [수주 ▼] │ │ +│ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ 납품처 │ │ 납품장소 │ │ +│ │ [____________________] │ │ [____________________] │ │ +│ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ 배송방법 │ │ 담당자 │ │ +│ │ [택배 ▼] │ │ [____________________] │ │ +│ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ 메모 │ │ +│ │ [______________________________________________________]│ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ +├─────────────────────────────────────────────────────────────────┤ +│ [취소] [💾 저장] │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**필드 목록**: + +| 순서 | 필드 (컬럼명) | 라벨 | 입력 타입 | 필수 | 비고 | +|------|---------------|------|-----------|------|------| +| 1 | `order_no` | 수주번호 | text | ✅ | 자동채번 또는 수동입력 | +| 2 | `order_date` | 수주일 | date | ✅ | 기본값: 오늘 | +| 3 | `partner_id` | 거래처 | select | ✅ | 거래처 목록에서 선택 | +| 4 | `part_code` | 품목코드 | text | ✅ | 품목 검색 | +| 5 | `part_name` | 품명 | text | | 품목코드 선택 시 자동 입력 | +| 6 | `spec` | 규격 | text | | 품목코드 선택 시 자동 입력 | +| 7 | `material` | 재질 | text | | | +| 8 | `unit` | 단위 | select | | 옵션: EA, kg, L, Box 등 | +| 9 | `order_qty` | 수주수량 | number | ✅ | | +| 10 | `unit_price` | 단가 | number | ✅ | | +| 11 | `due_date` | 납기일 | date | | | +| 12 | `status` | 상태 | select | ✅ | 옵션: 수주, 진행중, 완료, 취소 | +| 13 | `delivery_partner_id` | 납품처 | text | | | +| 14 | `delivery_address` | 납품장소 | text | | | +| 15 | `shipping_method` | 배송방법 | select | | 옵션: 택배, 화물, 직송, 퀵서비스 등 | +| 16 | `manager_name` | 담당자 | text | | | +| 17 | `memo` | 메모 | textarea | | | + +#### Step 3: 버튼 배치 + +| 버튼 | 액션 타입 | 스타일 | 설정 | +|------|-----------|--------|------| +| 저장 | `저장` | primary | 저장 후 모달 닫기, 부모 화면 테이블 새로고침 | +| 취소 | `모달 닫기` | secondary | | + +--- + +## 4. 컴포넌트 연동 설정 + +### 4.1 이벤트 흐름 + +``` +[검색 입력] + │ + ▼ +v2-table-search-widget + │ onFilterChange + ▼ +v2-table-list (자동 재조회) + │ + ▼ +[데이터 표시] + │ + ▼ +v2-aggregation-widget (통계 업데이트) + + +[수주등록/수정 버튼 클릭] + │ + ▼ +[모달 열기] → [폼 입력] → [저장] + │ │ + │ ▼ + │ refreshTable 이벤트 + │ │ + └────────────────────────┘ + │ + ▼ + v2-table-list (재조회) + │ + ▼ + v2-aggregation-widget (통계 업데이트) +``` + +### 4.2 연동 설정 + +| 소스 컴포넌트 | 이벤트/액션 | 대상 컴포넌트 | 동작 | +|---------------|-------------|---------------|------| +| 검색 위젯 | onFilterChange | 테이블 리스트 | 필터 적용, 재조회 | +| 테이블 리스트 | onDataChange | 집계 위젯 | 통계 업데이트 | +| 수주등록 버튼 | click | 모달 | 빈 폼으로 모달 열기 | +| 수정 버튼 | click | 모달 | 선택 데이터가 채워진 폼 열기 (수정) | +| 삭제 버튼 | click | 테이블 리스트 | 선택 항목 삭제 | +| 출하계획 버튼 | click | 슬라이드 패널 | 선택 항목 기반 출하계획 생성 | +| 모달 저장 | afterSave | 테이블 리스트 | refreshTable | + +--- + +## 5. 사용자 사용 예시 시나리오 + +### 시나리오 1: 수주 조회 + +| 단계 | 사용자 동작 | 기대 결과 | +|------|-------------|-----------| +| 1 | 화면 진입 | 전체 수주 목록 표시, 통계(총 금액, 총 수량) 표시 | +| 2 | 거래처 필터를 "삼성전자"로 선택 | 자동 필터링, 통계 업데이트 | +| 3 | 상태를 "진행중"으로 선택 | 추가 필터링 | +| 4 | Group by에서 "거래처" 선택 | 거래처별 그룹핑 표시 | + +### 시나리오 2: 수주 등록 + +| 단계 | 사용자 동작 | 기대 결과 | +|------|-------------|-----------| +| 1 | [수주 등록] 버튼 클릭 | 빈 폼 모달 표시 | +| 2 | 거래처 선택, 품목코드 입력 | 품명, 규격 자동 입력 | +| 3 | 수주수량, 단가 입력 | 금액 자동 계산 | +| 4 | [저장] 버튼 클릭 | 저장 완료, 모달 닫힘, 목록 갱신, 통계 업데이트 | + +### 시나리오 3: 수주 수정 + +| 단계 | 사용자 동작 | 기대 결과 | +|------|-------------|-----------| +| 1 | 테이블에서 행 체크박스 선택 | 행 선택 표시 | +| 2 | [수정] 버튼 클릭 | 수정 모달 표시 (기존 데이터 로드) | +| 3 | 데이터 수정 | 필드 값 변경 | +| 4 | [저장] 버튼 클릭 | 저장 완료, 목록 갱신 | + +### 시나리오 4: 수주 삭제 + +| 단계 | 사용자 동작 | 기대 결과 | +|------|-------------|-----------| +| 1 | 삭제할 행 체크박스 선택 (다중 가능) | 행 선택 표시 | +| 2 | [삭제] 버튼 클릭 | 삭제 확인 다이얼로그 표시 | +| 3 | 확인 | 삭제 완료, 목록 갱신, 통계 업데이트 | + +### 시나리오 5: 출하계획 생성 + +| 단계 | 사용자 동작 | 기대 결과 | +|------|-------------|-----------| +| 1 | 출하할 수주 행 체크박스 선택 (다중) | 행 선택 표시 | +| 2 | [출하계획] 버튼 클릭 | 출하계획 슬라이드 패널 열림 | +| 3 | 출하 수량 입력, 출하일 선택 | 출하계획 데이터 설정 | +| 4 | [적용] 버튼 클릭 | 출하계획 저장, 수주 데이터 업데이트 | + +--- + +## 6. 검증 체크리스트 + +### 기본 기능 +- [ ] 데이터 조회가 정상 동작하는가? +- [ ] 검색 필터 (수주번호, 거래처, 품목명, 상태, 수주일)가 정상 동작하는가? +- [ ] 신규 등록이 정상 동작하는가? +- [ ] 수정이 정상 동작하는가? +- [ ] 삭제가 정상 동작하는가? +- [ ] 엑셀 업로드가 정상 동작하는가? +- [ ] 엑셀 다운로드가 정상 동작하는가? + +### 테이블 기능 +- [ ] 페이지네이션이 정상 동작하는가? +- [ ] 정렬이 정상 동작하는가? +- [ ] 컬럼 너비 조정이 정상 동작하는가? +- [ ] 체크박스 선택이 정상 동작하는가? +- [ ] 수평 스크롤이 정상 동작하는가? + +### 검색 위젯 연동 +- [ ] v2-table-search-widget과 v2-table-list 연동이 정상 동작하는가? +- [ ] 필터 변경 시 자동 재조회가 동작하는가? +- [ ] 초기화 버튼이 정상 동작하는가? + +### 그룹핑 기능 +- [ ] Group by 선택 시 그룹핑이 정상 동작하는가? +- [ ] 그룹 헤더에 건수, 수량, 금액이 표시되는가? +- [ ] 그룹 접기/펼치기가 정상 동작하는가? + +### 통계 기능 +- [ ] 총 금액이 정확히 계산되는가? +- [ ] 총 수량이 정확히 계산되는가? +- [ ] 필터링 시 통계가 업데이트되는가? + +### 출하계획 연동 +- [ ] 선택한 수주를 기반으로 출하계획을 생성할 수 있는가? +- [ ] 출하계획 적용 후 수주 데이터가 업데이트되는가? + +--- + +## 7. 참고 사항 + +### 관련 테이블 +- `customer_mng` - 거래처 정보 (partner_id 참조) +- `item_info` - 품목 정보 (part_code 참조) +- `sales_order_detail` - 수주 상세 (다중 품목 관리 시) +- `shipment_mng` - 출하 정보 (출하계획 연동) + +### 특이 사항 +- `partner_id`는 거래처 테이블의 ID를 참조 (조인 필요) +- `balance_qty` = `order_qty` - `ship_qty` (잔량 자동 계산) +- `total_amount` = `order_qty` × `unit_price` (금액 자동 계산) +- 상태별 뱃지 색상: + - 수주: 파란색 (#dbeafe, #1e40af) + - 진행중: 노란색 (#fef3c7, #92400e) + - 완료: 초록색 (#d1fae5, #065f46) + - 취소: 빨간색 (#fee2e2, #991b1b) +- 수출용 필드: incoterms, payment_term, port_of_loading, port_of_discharge, hs_code, currency + +--- + +## 8. DB INSERT용 JSON 설정 (screen_layouts_v2 방식) + +> 📌 실제 화면 저장은 `screen_definitions` + `screen_layouts_v2` 테이블을 사용합니다. + +> ⚠️ **주의: 아래 JSON은 "수주관리" 화면 전용 예시입니다!** + +### 8.1 화면 정의 (screen_definitions) + +**필수 입력 필드:** + +```json +{ + "screenName": "수주관리", + "tableName": "sales_order_mng", + "companyCode": "COMPANY_7", + "description": "수주 관리 화면" +} +``` + +### 8.2 레이아웃 데이터 (screen_layouts_v2.layout_data) + +```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": 800 }, + "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": "order_no", "searchable": true, "displayName": "수주번호" }, + { "align": "left", "order": 1, "format": "text", "visible": true, "sortable": true, "columnName": "partner_id", "searchable": true, "displayName": "거래처" }, + { "align": "left", "order": 2, "format": "text", "visible": true, "sortable": true, "columnName": "part_code", "searchable": true, "displayName": "품목코드" }, + { "align": "left", "order": 3, "format": "text", "visible": true, "sortable": true, "columnName": "part_name", "searchable": true, "displayName": "품명" }, + { "align": "left", "order": 4, "format": "text", "visible": true, "sortable": true, "columnName": "spec", "searchable": true, "displayName": "규격" }, + { "align": "left", "order": 5, "format": "text", "visible": true, "sortable": true, "columnName": "material", "searchable": true, "displayName": "재질" }, + { "align": "right", "order": 6, "format": "number", "visible": true, "sortable": true, "columnName": "order_qty", "searchable": false, "displayName": "수주수량" }, + { "align": "right", "order": 7, "format": "number", "visible": true, "sortable": true, "columnName": "ship_qty", "searchable": false, "displayName": "출하수량" }, + { "align": "right", "order": 8, "format": "number", "visible": true, "sortable": true, "columnName": "balance_qty", "searchable": false, "displayName": "잔량" }, + { "align": "right", "order": 9, "format": "number", "visible": true, "sortable": true, "columnName": "inventory_qty", "searchable": false, "displayName": "현재고" }, + { "align": "right", "order": 10, "format": "number", "visible": true, "sortable": true, "columnName": "plan_ship_qty", "searchable": false, "displayName": "출하계획량" }, + { "align": "right", "order": 11, "format": "number", "visible": true, "sortable": true, "columnName": "unit_price", "searchable": false, "displayName": "단가" }, + { "align": "right", "order": 12, "format": "number", "visible": true, "sortable": true, "columnName": "total_amount", "searchable": false, "displayName": "금액" }, + { "align": "left", "order": 13, "format": "text", "visible": true, "sortable": true, "columnName": "delivery_partner_id", "searchable": true, "displayName": "납품처" }, + { "align": "left", "order": 14, "format": "text", "visible": true, "sortable": true, "columnName": "delivery_address", "searchable": true, "displayName": "납품장소" }, + { "align": "center", "order": 15, "format": "text", "visible": true, "sortable": true, "columnName": "shipping_method", "searchable": true, "displayName": "배송방법" }, + { "align": "center", "order": 16, "format": "date", "visible": true, "sortable": true, "columnName": "due_date", "searchable": false, "displayName": "납기일" }, + { "align": "center", "order": 17, "format": "date", "visible": true, "sortable": true, "columnName": "order_date", "searchable": false, "displayName": "수주일" }, + { "align": "center", "order": 18, "format": "text", "visible": true, "sortable": true, "columnName": "status", "searchable": true, "displayName": "상태" }, + { "align": "left", "order": 19, "format": "text", "visible": true, "sortable": true, "columnName": "manager_name", "searchable": true, "displayName": "담당자" }, + { "align": "left", "order": 20, "format": "text", "visible": true, "sortable": true, "columnName": "memo", "searchable": true, "displayName": "메모" } + ], + "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": "sales_order_mng", + "webTypeConfig": {}, + "horizontalScroll": { "enabled": true, "maxColumnWidth": 300, "minColumnWidth": 80, "maxVisibleColumns": 10 } + }, + "displayOrder": 1 + }, + { + "id": "comp_btn_user_options", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 1500, "y": 30, "z": 1 }, + "overrides": { + "text": "사용자옵션", + "type": "v2-button-primary", + "label": "사용자옵션 버튼", + "action": { "type": "custom" }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 2 + }, + { + "id": "comp_btn_upload", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 1610, "y": 30, "z": 1 }, + "overrides": { + "text": "엑셀 업로드", + "type": "v2-button-primary", + "label": "엑셀 업로드 버튼", + "action": { "type": "excel_upload" }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 3 + }, + { + "id": "comp_btn_download", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 1720, "y": 30, "z": 1 }, + "overrides": { + "text": "엑셀 다운로드", + "type": "v2-button-primary", + "label": "엑셀 다운로드 버튼", + "action": { "type": "excel_download" }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 4 + }, + { + "id": "comp_btn_register", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 1500, "y": 100, "z": 1 }, + "overrides": { + "text": "수주 등록", + "type": "v2-button-primary", + "label": "수주 등록 버튼", + "action": { + "type": "modal", + "modalSize": "lg", + "modalTitle": "수주 등록", + "targetScreenId": "{{modal_screen_id}}", + "successMessage": "저장되었습니다.", + "errorMessage": "저장 중 오류가 발생했습니다." + }, + "variant": "success", + "actionType": "button", + "webTypeConfig": { "variant": "default", "actionType": "custom" } + }, + "displayOrder": 5 + }, + { + "id": "comp_btn_edit", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 80, "height": 40 }, + "position": { "x": 1610, "y": 100, "z": 1 }, + "overrides": { + "text": "수정", + "type": "v2-button-primary", + "label": "수정 버튼", + "action": { + "type": "edit", + "modalSize": "lg", + "modalTitle": "수주 수정", + "targetScreenId": "{{modal_screen_id}}", + "successMessage": "수정되었습니다.", + "errorMessage": "수정 중 오류가 발생했습니다." + }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 6 + }, + { + "id": "comp_btn_delete", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 80, "height": 40 }, + "position": { "x": 1700, "y": 100, "z": 1 }, + "overrides": { + "text": "삭제", + "type": "v2-button-primary", + "label": "삭제 버튼", + "action": { + "type": "delete", + "successMessage": "삭제되었습니다.", + "errorMessage": "삭제 중 오류가 발생했습니다." + }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 7 + }, + { + "id": "comp_btn_shipment", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 1790, "y": 100, "z": 1 }, + "overrides": { + "text": "출하계획", + "type": "v2-button-primary", + "label": "출하계획 버튼", + "action": { "type": "custom" }, + "variant": "secondary", + "actionType": "button", + "webTypeConfig": { "variant": "secondary", "actionType": "custom" } + }, + "displayOrder": 8 + } + ] +} +``` + +### 8.3 모달 화면 (수주 등록/수정) + +#### 화면 정의 (필수 입력) + +```json +{ + "screenName": "수주 등록/수정", + "tableName": "sales_order_mng", + "companyCode": "COMPANY_7", + "description": "수주 등록/수정 폼 화면" +} +``` + +#### 레이아웃 데이터 (screen_layouts_v2.layout_data) + +```json +{ + "version": "2.0", + "components": [ + { + "id": "comp_order_no", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 20, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "수주번호", + "fieldName": "order_no", + "placeholder": "수주번호를 입력하세요", + "required": true + }, + "displayOrder": 0 + }, + { + "id": "comp_order_date", + "url": "@/lib/registry/components/v2-date", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 20, "z": 1 }, + "overrides": { + "type": "v2-date", + "label": "수주일", + "fieldName": "order_date", + "required": true + }, + "displayOrder": 1 + }, + { + "id": "comp_partner_id", + "url": "@/lib/registry/components/v2-select", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 100, "z": 1 }, + "overrides": { + "type": "v2-select", + "label": "거래처", + "fieldName": "partner_id", + "required": true, + "config": { + "mode": "dropdown", + "source": "table", + "sourceTable": "customer_mng", + "valueField": "id", + "labelField": "name" + } + }, + "displayOrder": 2 + }, + { + "id": "comp_part_code", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 100, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "품목코드", + "fieldName": "part_code", + "placeholder": "품목코드를 입력하세요", + "required": true + }, + "displayOrder": 3 + }, + { + "id": "comp_part_name", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 180, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "품명", + "fieldName": "part_name", + "placeholder": "품명을 입력하세요" + }, + "displayOrder": 4 + }, + { + "id": "comp_spec", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 180, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "규격", + "fieldName": "spec", + "placeholder": "규격을 입력하세요" + }, + "displayOrder": 5 + }, + { + "id": "comp_material", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 260, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "재질", + "fieldName": "material", + "placeholder": "재질을 입력하세요" + }, + "displayOrder": 6 + }, + { + "id": "comp_order_qty", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 260, "z": 1 }, + "overrides": { + "type": "v2-input", + "inputType": "number", + "label": "수주수량", + "fieldName": "order_qty", + "placeholder": "수주수량을 입력하세요", + "required": true + }, + "displayOrder": 7 + }, + { + "id": "comp_unit_price", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 340, "z": 1 }, + "overrides": { + "type": "v2-input", + "inputType": "number", + "label": "단가", + "fieldName": "unit_price", + "placeholder": "단가를 입력하세요", + "required": true + }, + "displayOrder": 8 + }, + { + "id": "comp_due_date", + "url": "@/lib/registry/components/v2-date", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 340, "z": 1 }, + "overrides": { + "type": "v2-date", + "label": "납기일", + "fieldName": "due_date" + }, + "displayOrder": 9 + }, + { + "id": "comp_status", + "url": "@/lib/registry/components/v2-select", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 420, "z": 1 }, + "overrides": { + "type": "v2-select", + "label": "상태", + "fieldName": "status", + "required": true, + "config": { + "mode": "dropdown", + "source": "static", + "options": [ + { "value": "수주", "label": "수주" }, + { "value": "진행중", "label": "진행중" }, + { "value": "완료", "label": "완료" }, + { "value": "취소", "label": "취소" } + ] + } + }, + "displayOrder": 10 + }, + { + "id": "comp_shipping_method", + "url": "@/lib/registry/components/v2-select", + "size": { "width": 300, "height": 60 }, + "position": { "x": 340, "y": 420, "z": 1 }, + "overrides": { + "type": "v2-select", + "label": "배송방법", + "fieldName": "shipping_method", + "config": { + "mode": "dropdown", + "source": "static", + "options": [ + { "value": "택배", "label": "택배" }, + { "value": "화물", "label": "화물" }, + { "value": "직송", "label": "직송" }, + { "value": "퀵서비스", "label": "퀵서비스" }, + { "value": "해상운송", "label": "해상운송" } + ] + } + }, + "displayOrder": 11 + }, + { + "id": "comp_delivery_address", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 620, "height": 60 }, + "position": { "x": 20, "y": 500, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "납품장소", + "fieldName": "delivery_address", + "placeholder": "납품장소를 입력하세요" + }, + "displayOrder": 12 + }, + { + "id": "comp_manager_name", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 300, "height": 60 }, + "position": { "x": 20, "y": 580, "z": 1 }, + "overrides": { + "type": "v2-input", + "label": "담당자", + "fieldName": "manager_name", + "placeholder": "담당자를 입력하세요" + }, + "displayOrder": 13 + }, + { + "id": "comp_memo", + "url": "@/lib/registry/components/v2-input", + "size": { "width": 620, "height": 80 }, + "position": { "x": 20, "y": 660, "z": 1 }, + "overrides": { + "type": "v2-input", + "inputType": "textarea", + "label": "메모", + "fieldName": "memo", + "placeholder": "메모를 입력하세요" + }, + "displayOrder": 14 + }, + { + "id": "comp_btn_save", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 540, "y": 760, "z": 1 }, + "overrides": { + "text": "저장", + "type": "v2-button-primary", + "label": "저장 버튼", + "action": { + "type": "save", + "closeModalAfterSave": true, + "refreshParentTable": true, + "successMessage": "저장되었습니다.", + "errorMessage": "저장 중 오류가 발생했습니다." + }, + "variant": "primary", + "actionType": "button" + }, + "displayOrder": 15 + } + ] +} +``` + +### 8.4 화면 생성 순서 (중요!) + +``` +1. 모달 화면 생성 (screen_definitions INSERT) + │ + ▼ +2. 모달 레이아웃 저장 (screen_layouts_v2 INSERT) + │ + ▼ +3. 메인 화면 생성 (screen_definitions INSERT) + │ + ▼ +4. 메인 레이아웃 저장 (screen_layouts_v2 INSERT) + └── targetScreenId에 모달 screen_id 사용! + │ + ▼ +5. (선택) 메뉴에 화면 연결 +``` + +--- + +## 9. 화면 구현 체크리스트 + +> 📋 새로운 화면을 구현할 때 아래 체크리스트를 순서대로 확인하세요. + +### 9.1 분석 단계 + +| 체크 | 항목 | 설명 | +|:----:|------|------| +| ☐ | **테이블 구조 분석** | `sales_order_mng` 테이블 스키마 확인 완료 | +| ☐ | **화면 기능 파악** | 조회/등록/수정/삭제, 검색, 필터, 그룹핑, 출하계획 연동 | +| ☐ | **컴포넌트 매핑** | 필요 기능 → V2 컴포넌트 매핑 완료 | +| ☐ | **구현 불가 항목 확인** | 현재 V2 컴포넌트로 구현 가능 | + +### 9.2 INSERT 후 검증 + +| 체크 | 항목 | 설명 | +|:----:|------|------| +| ☐ | **화면 접속 테스트** | `/screens/{screen_id}` URL로 접속 | +| ☐ | **컴포넌트 렌더링 확인** | 모든 컴포넌트가 정상 표시되는지 확인 | +| ☐ | **검색 기능 테스트** | 검색 위젯 동작 확인 | +| ☐ | **테이블 데이터 로드** | 테이블에 데이터 표시되는지 확인 | +| ☐ | **버튼 동작 테스트** | 등록/수정/삭제/출하계획 버튼 동작 확인 | +| ☐ | **모달 폼 테스트** | 모달 열림, 입력 필드 표시, 저장 동작 확인 | +| ☐ | **통계 업데이트** | 총 금액, 총 수량이 정확히 표시되는지 확인 | + +--- + +## 10. 메뉴에 화면 연결하기 + +> 📋 화면 생성 후, 특정 메뉴에 연결하여 사용자가 접근할 수 있도록 설정합니다. + +### 10.1 메뉴 연결 절차 + +``` +1. 대상 메뉴 찾기 (menu_info 테이블에서 objid 확인) + │ + ▼ +2. screen_menu_assignments 테이블에 할당 레코드 INSERT + │ + ▼ +3. menu_info 테이블의 menu_url, screen_code 업데이트 + │ + ▼ +4. 연결 결과 확인 +``` + +### 10.2 메뉴 찾기 + +```sql +-- 메뉴 이름으로 검색 +SELECT objid, menu_name_kor, menu_url, screen_code, company_code +FROM menu_info +WHERE menu_name_kor = '55566' -- 메뉴 이름 + AND company_code = 'COMPANY_19'; -- 회사 코드 + +-- 결과 예시: +-- objid: 1769415229091 +``` + +### 10.3 기존 할당 확인 및 제거 (중복 방지) + +> ⚠️ **중요**: 새 화면을 할당하기 전에 해당 메뉴에 이미 할당된 화면이 있는지 확인해야 합니다. 중복 할당 시 화면이 정상적으로 표시되지 않을 수 있습니다. + +```sql +-- 1. 해당 메뉴에 이미 할당된 화면 확인 +SELECT + sma.assignment_id, + sma.screen_id, + sd.screen_name, + sd.screen_code +FROM screen_menu_assignments sma +JOIN screen_definitions sd ON sma.screen_id = sd.screen_id +WHERE sma.menu_objid = '1769415229091'; -- 대상 메뉴 objid + +-- 2. 기존 할당이 있다면 삭제 +DELETE FROM screen_menu_assignments +WHERE menu_objid = '1769415229091'; -- 모든 기존 할당 삭제 + +-- 또는 특정 화면만 남기고 삭제 +DELETE FROM screen_menu_assignments +WHERE menu_objid = '1769415229091' + AND screen_id != 3733; -- 3733(수주관리)만 남기고 삭제 +``` + +### 10.4 화면-메뉴 할당 INSERT + +```sql +-- screen_menu_assignments에 할당 레코드 추가 +INSERT INTO screen_menu_assignments ( + screen_id, + menu_objid, + company_code, + display_order, + is_active, + created_date +) VALUES ( + 3733, -- 메인 화면의 screen_id + '1769415229091', -- menu_info의 objid (문자열로 저장) + 'COMPANY_19', -- 회사 코드 + 1, -- 표시 순서 + 'Y', -- 활성화 여부 + NOW() +) RETURNING assignment_id; +``` + +### 10.6 메뉴 URL 및 screen_code 업데이트 (필수!) + +> ⚠️ **중요**: `screen_menu_assignments`에 레코드를 추가해도 `menu_info`의 `menu_url`과 `screen_code`를 업데이트하지 않으면 메뉴 클릭 시 화면이 표시되지 않습니다. + +```sql +-- menu_info 테이블의 menu_url, screen_code 업데이트 +UPDATE menu_info +SET menu_url = '/screens/3733', -- 화면 URL + screen_code = 'COMPANY_19_SO_MAIN' -- 화면 코드 +WHERE objid = 1769415229091; +``` + +### 10.7 연결 확인 + +```sql +-- 메뉴-화면 연결 상태 확인 +SELECT + mi.objid, + mi.menu_name_kor, + mi.menu_url, + mi.screen_code, + sd.screen_id, + sd.screen_name +FROM menu_info mi +JOIN screen_definitions sd ON mi.screen_code = sd.screen_code +WHERE mi.objid = 1769415229091; + +-- 예상 결과: +-- objid: 1769415229091 +-- menu_name_kor: 55566 +-- menu_url: /screens/3733 +-- screen_code: COMPANY_19_SO_MAIN +-- screen_id: 3733 +-- screen_name: 수주관리 +``` + +### 10.8 전체 SQL 예시 (수주관리 화면 → 55566 메뉴) + +```sql +-- 1. 메뉴 찾기 +SELECT objid, menu_name_kor FROM menu_info +WHERE menu_name_kor = '55566' AND company_code = 'COMPANY_19'; +-- 결과: objid = 1769415229091 + +-- 2. 기존 할당 확인 및 삭제 (중복 방지!) +SELECT sma.assignment_id, sma.screen_id, sd.screen_name +FROM screen_menu_assignments sma +JOIN screen_definitions sd ON sma.screen_id = sd.screen_id +WHERE sma.menu_objid = '1769415229091'; + +-- 기존 할당이 있다면 삭제 +DELETE FROM screen_menu_assignments +WHERE menu_objid = '1769415229091'; + +-- 3. 새 화면 할당 +INSERT INTO screen_menu_assignments (screen_id, menu_objid, company_code, display_order, is_active, created_date) +VALUES (3733, '1769415229091', 'COMPANY_19', 1, 'Y', NOW()); + +-- 4. 메뉴 URL 업데이트 (필수!) +UPDATE menu_info +SET menu_url = '/screens/3733', + screen_code = 'COMPANY_19_SO_MAIN' +WHERE objid = 1769415229091; +``` + +### 10.9 메뉴 연결 체크리스트 + +| 체크 | 항목 | 설명 | +|:----:|------|------| +| ☐ | **대상 메뉴 확인** | `menu_info`에서 메뉴 objid 확인 | +| ☐ | **기존 할당 확인** | `screen_menu_assignments`에서 중복 할당 여부 확인 | +| ☐ | **기존 할당 삭제** | 중복 할당이 있다면 기존 레코드 DELETE | +| ☐ | **새 화면 할당 INSERT** | `screen_menu_assignments` 테이블에 새 레코드 추가 | +| ☐ | **menu_url 업데이트** | `/screens/{screen_id}` 형식으로 업데이트 | +| ☐ | **screen_code 업데이트** | 화면의 screen_code로 업데이트 | +| ☐ | **메뉴 클릭 테스트** | 해당 회사로 로그인하여 메뉴 클릭 시 화면 표시 확인 | diff --git a/docs/screen-implementation-guide/02_sales/quote.md b/docs/screen-implementation-guide/02_sales/quote.md new file mode 100644 index 00000000..eac09315 --- /dev/null +++ b/docs/screen-implementation-guide/02_sales/quote.md @@ -0,0 +1,308 @@ +# 견적관리 화면 구현 가이드 + +> **화면명**: 견적관리 +> **파일**: 견적관리.html +> **분류**: 영업관리 +> **구현 가능**: ✅ 완전 (현재 V2 컴포넌트) + +--- + +## 1. 화면 개요 + +견적서 생성 및 관리 화면으로, 고객 요청에 대한 견적을 작성하고 수주로 전환합니다. + +### 핵심 기능 +- 견적 목록 조회/검색 +- 견적 등록/수정/삭제 +- 견적 상세 및 품목 내역 관리 +- 견적서 인쇄/PDF 출력 +- 수주 전환 + +--- + +## 2. 화면 레이아웃 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ [기간] [거래처] [견적번호] [품목명] [상태▼] [초기화][조회] │ +│ [사용자옵션][업로드][다운로드]│ +├───────────────────────┬─────────────────────────────────────────┤ +│ 📋 견적 목록 │ 📄 견적 상세 │ +│ ─────────────── │ [인쇄] [복사] [수주전환] [수정] [삭제] │ +│ [신규등록] │ ───────────────────────── │ +│ ┌──────────────────┐ │ 견적번호: QT-2026-0001 │ +│ │견적번호|거래처|금액..│ │ 거래처: (주)테스트 │ +│ │QT-001 |A사|1,000..│ │ 견적일: 2026-01-30 │ +│ │QT-002 |B사|2,500..│ ├─────────────────────────────────────────┤ +│ └──────────────────┘ │ [기본정보] [품목내역] [첨부파일] │ +│ │ ─────────────────────────── │ +│ 리사이저 ↔ │ │품목코드|품목명|수량|단가|금액|비고│ │ +│ │ │P-001 |제품A|100|1,000|100,000| │ │ +└───────────────────────┴─────────────────────────────────────────┘ +``` + +--- + +## 3. V2 컴포넌트 매핑 + +| HTML 영역 | V2 컴포넌트 | 상태 | +|-----------|-------------|------| +| 검색 섹션 | `v2-table-search-widget` | ✅ 가능 | +| 견적 목록 | `v2-table-list` | ✅ 가능 | +| 분할 패널 | `v2-split-panel-layout` | ✅ 가능 | +| 상세 탭 | `v2-tabs-widget` | ✅ 가능 | +| 품목 내역 테이블 | `v2-table-list` | ✅ 가능 | + +--- + +## 4. 테이블 정의 + +### 4.1 견적 목록 (좌측) + +```typescript +columns: [ + { id: 'checkbox', type: 'checkbox', width: 50 }, + { id: 'quote_no', label: '견적번호', width: 120 }, + { id: 'quote_date', label: '견적일', width: 100 }, + { id: 'customer_name', label: '거래처', width: 150 }, + { id: 'total_amount', label: '견적금액', width: 120, align: 'right', format: 'currency' }, + { id: 'status', label: '상태', width: 80 }, + { id: 'valid_date', label: '유효기간', width: 100 }, + { id: 'manager', label: '담당자', width: 100 } +] +``` + +### 4.2 품목 내역 (우측 탭) + +```typescript +detailColumns: [ + { id: 'seq', label: 'No', width: 50 }, + { id: 'item_code', label: '품목코드', width: 100 }, + { id: 'item_name', label: '품목명', width: 200 }, + { id: 'spec', label: '규격', width: 150 }, + { id: 'quantity', label: '수량', width: 80, align: 'right' }, + { id: 'unit', label: '단위', width: 60 }, + { id: 'unit_price', label: '단가', width: 100, align: 'right', format: 'currency' }, + { id: 'amount', label: '금액', width: 120, align: 'right', format: 'currency' }, + { id: 'remark', label: '비고', width: 150 } +] +``` + +--- + +## 5. 검색 조건 + +| 필드명 | 컴포넌트 | 설정 | +|--------|----------|------| +| 기간 | `v2-date` | dateRange: true | +| 거래처 | `v2-input` | placeholder: "거래처" | +| 견적번호 | `v2-input` | placeholder: "견적번호" | +| 품목명 | `v2-input` | placeholder: "품목명" | +| 상태 | `v2-select` | 작성중, 제출, 승인, 반려, 수주전환 | + +--- + +## 6. 상세 탭 구성 + +```typescript +tabs: [ + { + id: 'basic', + label: '기본정보', + fields: [ + { id: 'quote_no', label: '견적번호' }, + { id: 'quote_date', label: '견적일' }, + { id: 'customer_code', label: '거래처코드' }, + { id: 'customer_name', label: '거래처명' }, + { id: 'manager', label: '담당자' }, + { id: 'valid_date', label: '유효기간' }, + { id: 'delivery_date', label: '납기일' }, + { id: 'payment_term', label: '결제조건' }, + { id: 'remark', label: '비고' } + ] + }, + { + id: 'items', + label: '품목내역', + type: 'table', + entityId: 'quote_items' + }, + { + id: 'files', + label: '첨부파일', + type: 'file-list' + } +] +``` + +--- + +## 7. 버튼 액션 + +### 7.1 목록 버튼 +| 버튼 | 액션 | +|------|------| +| 신규등록 | 견적 등록 모달 열기 | + +### 7.2 상세 버튼 +| 버튼 | 액션 | +|------|------| +| 인쇄 | 견적서 PDF 출력 | +| 복사 | 선택 견적 복사하여 신규 생성 | +| 수주전환 | 견적 → 수주 데이터 생성 | +| 수정 | 견적 수정 모달 열기 | +| 삭제 | 견적 삭제 (확인 후) | + +--- + +## 8. 구현 JSON + +```json +{ + "screen_code": "QUOTE_MAIN", + "screen_name": "견적관리", + "components": [ + { + "type": "v2-table-search-widget", + "position": { "x": 0, "y": 0, "w": 12, "h": 2 }, + "config": { + "searchFields": [ + { "type": "date", "id": "date_range", "placeholder": "기간", "dateRange": true }, + { "type": "input", "id": "customer_name", "placeholder": "거래처" }, + { "type": "input", "id": "quote_no", "placeholder": "견적번호" }, + { "type": "input", "id": "item_name", "placeholder": "품목명" }, + { "type": "select", "id": "status", "placeholder": "상태", + "options": [ + { "value": "draft", "label": "작성중" }, + { "value": "submitted", "label": "제출" }, + { "value": "approved", "label": "승인" }, + { "value": "rejected", "label": "반려" }, + { "value": "converted", "label": "수주전환" } + ] + } + ], + "buttons": [ + { "label": "초기화", "action": "reset", "variant": "outline" }, + { "label": "조회", "action": "search", "variant": "primary" } + ], + "rightButtons": [ + { "label": "사용자옵션", "action": "userOptions", "variant": "outline" }, + { "label": "엑셀업로드", "action": "excelUpload", "variant": "outline" }, + { "label": "엑셀다운로드", "action": "excelDownload", "variant": "outline" } + ] + } + }, + { + "type": "v2-split-panel-layout", + "position": { "x": 0, "y": 2, "w": 12, "h": 10 }, + "config": { + "masterPanel": { + "title": "견적 목록", + "entityId": "quote_header", + "buttons": [ + { "label": "신규등록", "action": "create", "variant": "primary" } + ], + "columns": [ + { "id": "quote_no", "label": "견적번호", "width": 120 }, + { "id": "quote_date", "label": "견적일", "width": 100 }, + { "id": "customer_name", "label": "거래처", "width": 150 }, + { "id": "total_amount", "label": "견적금액", "width": 120, "align": "right" }, + { "id": "status", "label": "상태", "width": 80 }, + { "id": "manager", "label": "담당자", "width": 100 } + ] + }, + "detailPanel": { + "title": "견적 상세", + "buttons": [ + { "label": "인쇄", "action": "print", "variant": "outline" }, + { "label": "복사", "action": "copy", "variant": "outline" }, + { "label": "수주전환", "action": "convert", "variant": "secondary" }, + { "label": "수정", "action": "edit", "variant": "outline" }, + { "label": "삭제", "action": "delete", "variant": "destructive" } + ], + "tabs": [ + { + "id": "basic", + "label": "기본정보", + "type": "form" + }, + { + "id": "items", + "label": "품목내역", + "type": "table", + "entityId": "quote_items", + "relationType": "one-to-many", + "relationKey": "quote_id" + }, + { + "id": "files", + "label": "첨부파일", + "type": "file" + } + ] + }, + "defaultRatio": 40, + "resizable": true + } + } + ] +} +``` + +--- + +## 9. 데이터베이스 테이블 + +### quote_header (견적 헤더) +```sql +CREATE TABLE quote_header ( + id SERIAL PRIMARY KEY, + company_code VARCHAR(20) NOT NULL, + quote_no VARCHAR(50) NOT NULL, + quote_date DATE NOT NULL, + customer_code VARCHAR(50), + customer_name VARCHAR(200), + total_amount NUMERIC(15,2), + tax_amount NUMERIC(15,2), + status VARCHAR(20) DEFAULT 'draft', + valid_date DATE, + delivery_date DATE, + payment_term VARCHAR(100), + manager VARCHAR(100), + remark TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); +``` + +### quote_items (견적 품목) +```sql +CREATE TABLE quote_items ( + id SERIAL PRIMARY KEY, + company_code VARCHAR(20) NOT NULL, + quote_id INTEGER REFERENCES quote_header(id), + seq INTEGER, + item_code VARCHAR(50), + item_name VARCHAR(200), + spec VARCHAR(200), + quantity NUMERIC(15,3), + unit VARCHAR(20), + unit_price NUMERIC(15,2), + amount NUMERIC(15,2), + remark TEXT +); +``` + +--- + +## 10. 구현 체크리스트 + +- [x] 검색 영역: v2-table-search-widget +- [x] 분할 패널: v2-split-panel-layout +- [x] 목록 테이블: v2-table-list +- [x] 상세 탭: v2-tabs-widget +- [x] 품목 내역 테이블: v2-table-list (nested) +- [ ] 인쇄 기능: 별도 구현 필요 +- [ ] 수주 전환: 비즈니스 로직 구현 + +**현재 V2 컴포넌트로 100% 구현 가능** diff --git a/docs/screen-implementation-guide/03_production/.gitkeep b/docs/screen-implementation-guide/03_production/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/screen-implementation-guide/03_production/production-plan.md b/docs/screen-implementation-guide/03_production/production-plan.md new file mode 100644 index 00000000..22ef6a7a --- /dev/null +++ b/docs/screen-implementation-guide/03_production/production-plan.md @@ -0,0 +1,601 @@ +# 생산계획관리 (Production Plan Management) + +> ⚠️ **중요 안내**: 이 화면은 **복합형 레이아웃** (좌우 분할 패널 + 타임라인 스케줄러)으로, 현재 V2 컴포넌트만으로는 완전한 구현이 불가능합니다. 아래 문서는 화면 분석 및 향후 구현 계획을 위한 참조용입니다. + +--- + +## 1. 화면 개요 + +| 항목 | 내용 | +|------|------| +| **화면명** | 생산계획관리 | +| **영문명** | Production Plan Management | +| **화면 유형** | 복합형 (좌우 분할 패널 + 타임라인 스케줄러) | +| **메인 테이블** | `production_plan_mng` | +| **관련 테이블** | `sales_order_mng`, `item_info`, `equipment_info`, `bom_info` | +| **주요 기능** | 수주 기반 생산계획 수립, 타임라인 스케줄러, 자동 스케줄 생성, 반제품 계획 연동 | + +--- + +## 2. 화면 구조 분석 + +### 2.1 레이아웃 구조 + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ 검색 섹션 │ +│ [검색필드들...] [사용자옵션] [엑셀업로드] [엑셀다운로드] │ +├────────────────────────────────┬──┬──────────────────────────────────────────┤ +│ 왼쪽 패널 (50%, 리사이즈) │ │ 오른쪽 패널 (50%) │ +│ ┌────────────────────────────┐ │리│ ┌──────────────────────────────────────┐ │ +│ │ [수주데이터] [안전재고부족] │ │사│ │ [완제품 생산계획] [반제품 생산계획] │ │ +│ ├────────────────────────────┤ │이│ ├──────────────────────────────────────┤ │ +│ │ │ │즈│ │ │ │ +│ │ 수주 목록 테이블 │ │핸│ │ 타임라인 스케줄러 │ +│ │ (그룹화된 품목별 수주) │ │들│ │ (간트차트 형태) │ +│ │ │ │ │ │ │ │ +│ │ - 체크박스 │ │ │ │ - 날짜별 그리드 │ +│ │ - 접기/펼치기 토글 │ │ │ │ - 생산계획 바 (드래그 가능) │ +│ │ - 품목별 그룹 행 │ │ │ │ - 납기일 마커 │ +│ │ - 수주 상세 행 │ │ │ │ │ +│ │ │ │ │ │ │ +│ └────────────────────────────┘ │ │ └──────────────────────────────────────┘ │ +│ [계획에 없는 품목만] [선택품목 불러오기] [새로고침] │ [자동스케줄] [저장] [초기화] │ +└────────────────────────────────┴──┴──────────────────────────────────────────┘ +``` + +### 2.2 탭 구조 + +**왼쪽 패널 탭**: +1. **수주데이터**: 수주 목록 (품목별 그룹핑) +2. **안전재고 부족분**: 안전재고 미달 품목 목록 + +**오른쪽 패널 탭**: +1. **완제품 생산계획**: 완제품 타임라인 스케줄러 +2. **반제품 생산계획**: 반제품 타임라인 스케줄러 + +--- + +## 3. 테이블 정의 + +### 3.1 메인 테이블: `production_plan_mng` + +| 컬럼명 | 타입 | NULL | 설명 | +|--------|------|------|------| +| id | SERIAL | NO | PK | +| company_code | VARCHAR(20) | NO | 회사 코드 | +| plan_no | VARCHAR(50) | NO | 생산계획번호 | +| plan_date | DATE | NO | 계획일자 | +| item_code | VARCHAR(50) | NO | 품목코드 | +| item_name | VARCHAR(200) | YES | 품명 | +| plan_qty | NUMERIC(15,3) | NO | 계획수량 | +| start_date | DATE | NO | 시작일 | +| end_date | DATE | NO | 종료일 | +| due_date | DATE | YES | 납기일 | +| equipment_id | INTEGER | YES | 설비 ID (FK) | +| equipment_name | VARCHAR(100) | YES | 설비명 | +| status | VARCHAR(20) | YES | 상태 (계획/지시/진행/완료) | +| priority | VARCHAR(20) | YES | 우선순위 | +| work_shift | VARCHAR(20) | YES | 작업조 (주간/야간/주야) | +| manager_name | VARCHAR(100) | YES | 담당자 | +| work_order_no | VARCHAR(50) | YES | 작업지시번호 | +| remarks | TEXT | YES | 비고 | +| order_no | VARCHAR(50) | YES | 관련 수주번호 | +| partner_id | VARCHAR(50) | YES | 거래처 ID | +| hourly_capacity | NUMERIC(15,3) | YES | 시간당 생산능력 | +| daily_capacity | NUMERIC(15,3) | YES | 일일 생산능력 | +| lead_time | INTEGER | YES | 리드타임 (일) | +| product_type | VARCHAR(20) | YES | 제품유형 (완제품/반제품) | +| parent_plan_id | INTEGER | YES | 모품목 계획 ID (반제품용) | +| created_date | TIMESTAMPTZ | YES | 생성일시 | +| created_by | VARCHAR(50) | YES | 생성자 | +| updated_date | TIMESTAMPTZ | YES | 수정일시 | +| updated_by | VARCHAR(50) | YES | 수정자 | + +### 3.2 관련 테이블 + +#### `equipment_info` (설비 정보) + +| 컬럼명 | 타입 | 설명 | +|--------|------|------| +| id | SERIAL | PK | +| equipment_code | VARCHAR(50) | 설비코드 | +| equipment_name | VARCHAR(100) | 설비명 | +| equipment_type | VARCHAR(50) | 설비유형 | +| capacity_per_hour | NUMERIC(15,3) | 시간당 생산능력 | +| status | VARCHAR(20) | 상태 | + +--- + +## 4. 구현 가능 여부 분석 + +### 4.1 현재 V2 컴포넌트로 구현 가능한 기능 + +| 기능 | 가능 여부 | 사용 컴포넌트 | 비고 | +|------|:---------:|--------------|------| +| 검색 필터 | ✅ | `v2-table-search-widget` | | +| 기본 버튼 (엑셀, 사용자옵션) | ✅ | `v2-button-primary` | | +| 단일 테이블 목록 | ✅ | `v2-table-list` | | +| 기본 모달 폼 | ✅ | 모달 화면 | | +| 좌우 분할 패널 (기본) | ⚠️ | `v2-split-panel-layout` | 테이블/리스트만 표시 가능 | +| 탭 컴포넌트 (기본) | ⚠️ | `v2-tabs-widget` | 디자인 모드에서 컴포넌트 배치 | + +### 4.2 현재 V2 컴포넌트의 제한 사항 + +#### `v2-split-panel-layout` 제한 + +**현재 기능**: +- 좌우 분할 패널 (리사이즈 가능) +- 각 패널에 **테이블** 또는 **리스트** 표시 (`displayMode: "list" | "table"`) +- leftPanel ↔ rightPanel 관계 설정 (relation) +- 우측 패널에 추가 탭 (additionalTabs) + +**제한 사항**: +- ❌ 패널 안에 **임의의 컴포넌트** (타임라인 등)를 배치할 수 없음 +- ❌ **그룹화된 테이블** (접기/펼치기) 미지원 +- ❌ 복잡한 커스텀 UI 배치 불가 + +#### `v2-tabs-widget` 제한 + +**현재 기능**: +- 탭별 컴포넌트 자유 배치 +- 디자인 모드에서 드래그&드롭 + +**제한 사항**: +- ❌ 탭 내에 **다른 V2 컴포넌트**를 완전히 자유롭게 배치하기 어려움 +- ❌ 런타임에서 복잡한 컴포넌트 렌더링 제한 + +### 4.3 생산계획관리에 필요한 기능 vs 현재 지원 + +| 필요 기능 | 현재 지원 | 설명 | +|----------|:---------:|------| +| 좌우 분할 패널 | ⚠️ 부분 | `v2-split-panel-layout` - 테이블만 가능 | +| 왼쪽 패널 탭 (수주/안전재고) | ❌ | 분할 패널 내 탭 조합 미지원 | +| **그룹화된 테이블** (품목별 접기/펼치기) | ❌ | 신규 개발 필요 | +| 오른쪽 패널 탭 (완제품/반제품) | ❌ | 분할 패널 내 탭 조합 미지원 | +| **타임라인 스케줄러** (간트차트) | ❌ | 신규 개발 필요 | +| 드래그&드롭 스케줄 이동 | ❌ | 신규 개발 필요 | +| 복잡한 상세 모달 (분할, 설비할당) | ❌ | 커스텀 모달 개발 필요 | + +### 4.4 향후 개발 필요 컴포넌트 + +``` +필요 컴포넌트 목록: +1. v2-timeline-scheduler - 타임라인/간트차트 스케줄러 (핵심!) +2. v2-table-grouped - 그룹화된 테이블 (접기/펼치기) +3. v2-split-panel-enhanced - 패널 내 임의 컴포넌트 배치 가능한 확장판 +4. v2-modal-complex - 복잡한 모달 (분할, 다단계, 설비할당) +``` + +### 4.5 현재 구현 가능한 최대 범위 + +현재 V2 컴포넌트로 구현 가능한 **최대 범위**: + +``` +┌──────────────────────────────────────────────────────────────┐ +│ 검색 섹션 (v2-table-search-widget) │ +├──────────────────────────────────────────────────────────────┤ +│ │ +│ 생산계획 테이블 (v2-table-list) - 단일 테이블, 그룹화 없음 │ +│ │ +├──────────────────────────────────────────────────────────────┤ +│ [등록] [수정] [삭제] (v2-button-primary) │ +└──────────────────────────────────────────────────────────────┘ +``` + +**구현 불가능한 핵심 기능**: +- 품목별 그룹핑 (접기/펼치기) +- 간트차트 타임라인 +- 자동 스케줄 생성 +- 드래그로 스케줄 이동 + +--- + +## 5. 단순화된 구현 방안 (임시) + +> 현재 V2 컴포넌트만으로 **간소화된 버전**을 구현할 수 있습니다. + +### 5.1 간소화 버전 레이아웃 + +``` +┌──────────────────────────────────────────────────────────────┐ +│ 검색 섹션 │ +│ [품목코드] [품명] [계획기간] [상태] [사용자옵션] [엑셀다운로드] │ +├──────────────────────────────────────────────────────────────┤ +│ │ +│ 생산계획 목록 테이블 │ +│ (단일 테이블, 그룹화 없음) │ +│ │ +├──────────────────────────────────────────────────────────────┤ +│ [신규등록] [수정] [삭제] │ +└──────────────────────────────────────────────────────────────┘ +``` + +### 5.2 간소화 버전 테이블 컬럼 + +| 순서 | 컬럼명 | 표시명 | 정렬 | 형식 | +|:----:|--------|--------|:----:|------| +| 1 | plan_no | 계획번호 | left | text | +| 2 | plan_date | 계획일자 | center | date | +| 3 | item_code | 품목코드 | left | text | +| 4 | item_name | 품명 | left | text | +| 5 | plan_qty | 계획수량 | right | number | +| 6 | start_date | 시작일 | center | date | +| 7 | end_date | 종료일 | center | date | +| 8 | due_date | 납기일 | center | date | +| 9 | equipment_name | 설비 | left | text | +| 10 | status | 상태 | center | badge | +| 11 | manager_name | 담당자 | left | text | +| 12 | product_type | 제품유형 | center | text | + +### 5.3 간소화 버전 모달 필드 + +| 필드명 | 라벨 | 타입 | 필수 | +|--------|------|------|:----:| +| plan_no | 계획번호 | text | ✅ | +| plan_date | 계획일자 | date | ✅ | +| item_code | 품목코드 | select (품목 검색) | ✅ | +| item_name | 품명 | text (자동) | | +| plan_qty | 계획수량 | number | ✅ | +| start_date | 시작일 | date | ✅ | +| end_date | 종료일 | date | ✅ | +| due_date | 납기일 | date | | +| equipment_id | 설비 | select | | +| status | 상태 | select | ✅ | +| priority | 우선순위 | select | | +| work_shift | 작업조 | select | | +| manager_name | 담당자 | text | | +| remarks | 비고 | textarea | | +| product_type | 제품유형 | select | | + +--- + +## 6. 원본 HTML 기능 상세 분석 + +### 6.1 수주데이터 탭 (왼쪽 패널) + +**테이블 구조**: +- 품목별 그룹 행 (접기/펼치기 가능) +- 수주 상세 행 (그룹 행 하위) + +**품목 그룹 행 컬럼**: +| 컬럼 | 설명 | +|------|------| +| 체크박스 | 품목 그룹 선택 | +| 토글 | 상세 접기/펼치기 | +| 품목코드 | | +| 품목명 | | +| 총수주량 | 해당 품목의 모든 수주 합계 | +| 출고량 | | +| 잔량 | 총수주량 - 출고량 | +| 현재고 | | +| 안전재고 | | +| 출하계획량 | | +| 기생산계획량 | 이미 등록된 생산계획 수량 | +| 생산진행 | 현재 생산 중인 수량 | +| 필요생산계획 | 추가로 계획해야 할 수량 (빨간색 강조) | + +**수주 상세 행**: +- 수주번호, 거래처, 상태 배지 +- 수주량, 출고량, 잔량 +- 납기일 + +**버튼**: +- `계획에 없는 품목만` 체크박스 필터 +- `선택 품목 불러오기`: 선택한 품목을 생산계획으로 등록 +- `새로고침` + +### 6.2 안전재고 부족분 탭 (왼쪽 패널) + +**테이블 컬럼**: +| 컬럼 | 설명 | +|------|------| +| 체크박스 | | +| 품목코드 | | +| 품목명 | | +| 현재고 | | +| 안전재고 | | +| 부족수량 | 빨간색 (마이너스) | +| 권장생산량 | 녹색 | +| 최종입고일 | | + +### 6.3 완제품 생산계획 탭 (오른쪽 패널) + +**스케줄 옵션**: +- 안전리드타임 (일) +- 표시 기간 (주) +- 미진행 계획 재계산 체크박스 + +**범례**: +- 계획 (파란색) +- 지시 (주황색) +- 진행 (녹색) +- 완료 (회색) +- 납기일 (빨간 테두리) +- 긴급 (빨간 아이콘) + +**타임라인 구조**: +- 날짜별 헤더 (일/월 표시, 주말 강조, 오늘 강조) +- 품목별 행 +- 생산계획 바 (드래그로 이동 가능) +- 클릭 시 상세 모달 오픈 + +**버튼**: +- `새로고침` +- `자동 스케줄 생성`: 선택된 품목에 대해 자동으로 생산계획 생성 +- `선택 계획 병합`: 같은 품목의 계획을 하나로 병합 +- `선택 품목 → 반제품 계획`: BOM 기반 반제품 계획 생성 +- `저장` +- `초기화` + +### 6.4 반제품 생산계획 탭 (오른쪽 패널) + +**옵션**: +- 현재고 및 안전재고 감안 +- 진행중인 계획 유지하고 재계산 +- 투입 완료된 반제품 제외 + +**안내**: +- 완제품 생산계획 기준으로 필요한 반제품 계획 자동 생성 +- 모품목 생산 시작일 고려하여 납기일 설정 +- BOM(자재명세서) 정보 기반 필요 수량 계산 + +### 6.5 생산 스케줄 상세 모달 + +**기본 정보**: +- 품목코드 (읽기전용) +- 품목명 (읽기전용) + +**근거 정보**: +- 수주번호, 안전재고, 재고부족 등 표시 + +**생산 정보**: +- 총 생산수량 +- 납기일 (읽기전용) +- 계획 시작일 (수정 가능) +- 계획 종료일 (수정 가능) +- 생산 기간 (자동 계산) + +**과거 계획 경고**: +- 시작일이 과거인 경우 경고 표시 +- `오늘부터 재조정` 버튼 +- `작업지시 즉시 생성` 버튼 + +**계획 분할**: +- 분할 개수 선택 (2~4개) +- 각 분할 수량 입력 +- 분할 실행 + +**설비 할당**: +- 설비 선택 버튼 +- 선택된 설비 목록 + +**생산 상태**: +- 상태 (자동 관리): 계획됨/작업지시/진행중/완료 + +**추가 정보**: +- 담당자 +- 작업지시번호 +- 비고 + +**버튼**: +- 삭제 +- 취소 +- 저장 + +--- + +## 7. 구현 우선순위 + +### Phase 1: 간소화 버전 (현재 구현 가능) + +V2 컴포넌트로 기본 CRUD 화면 구현: +- 검색 위젯 +- 단일 테이블 (그룹화 없음) +- 기본 모달 폼 +- 상태 배지 + +### Phase 2: 컴포넌트 개발 후 + +1. `v2-tabs` 컴포넌트 개발 +2. `v2-split-panel` 컴포넌트 개발 +3. `v2-table-grouped` 컴포넌트 개발 + +### Phase 3: 타임라인 스케줄러 + +1. `v2-timeline-scheduler` 컴포넌트 개발 +2. 드래그&드롭 기능 +3. 자동 스케줄 생성 로직 +4. 반제품 연동 + +--- + +## 8. 참고 사항 + +### 8.1 상태 배지 스타일 + +| 상태 | 배경색 | 글자색 | 설명 | +|------|--------|--------|------| +| 계획 | #dbeafe | #1e40af | 파란색 | +| 지시 | #fef3c7 | #92400e | 주황색 | +| 진행 | #d1fae5 | #065f46 | 녹색 | +| 완료 | #f3f4f6 | #4b5563 | 회색 | +| 긴급 | #fee2e2 | #991b1b | 빨간색 | + +### 8.2 자동 스케줄 생성 로직 + +``` +1. 선택된 품목의 필요 생산수량 계산 + - 필요수량 = 잔량 + 안전재고 - 현재고 - 기생산계획량 + +2. 납기일에서 안전리드타임 차감하여 완료일 계산 + +3. 일일 생산능력으로 필요 생산일수 계산 + +4. 완료일에서 역산하여 시작일 계산 + +5. 설비 가용성 확인 및 자동 할당 + +6. 반제품이 필요한 경우 BOM 기반 반제품 계획 생성 +``` + +### 8.3 계획 분할 로직 + +``` +1. 원본 계획의 총 수량 확인 + +2. 분할 개수 선택 (2~4개) + +3. 각 분할 수량 입력 (합계 = 원본 수량) + +4. 분할 실행 시: + - 원본 계획 삭제 + - 새로운 N개의 계획 생성 + - 각각 별도의 시작일/종료일 설정 가능 +``` + +--- + +## 9. DB INSERT JSON (간소화 버전) + +> ⚠️ 이 JSON은 **간소화 버전**입니다. 전체 기능 구현 시 별도 개발이 필요합니다. + +### 9.1 screen_definitions + +```json +{ + "screen_name": "생산계획관리", + "screen_code": "{COMPANY_CODE}_PP_MAIN", + "table_name": "production_plan_mng", + "company_code": "{COMPANY_CODE}", + "description": "생산계획 관리 화면 (간소화 버전)", + "is_active": "Y", + "db_source_type": "internal", + "data_source_type": "database" +} +``` + +### 9.2 screen_layouts_v2.layout_data (간소화 버전) + +```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": "검색 필터" + }, + "displayOrder": 0 + }, + { + "id": "comp_table", + "url": "@/lib/registry/components/v2-table-list", + "size": { "width": 1920, "height": 700 }, + "position": { "x": 0, "y": 120, "z": 1 }, + "overrides": { + "type": "v2-table-list", + "label": "생산계획 목록", + "columns": [ + { "columnName": "plan_no", "displayName": "계획번호", "order": 0, "visible": true, "sortable": true, "format": "text", "align": "left" }, + { "columnName": "plan_date", "displayName": "계획일자", "order": 1, "visible": true, "sortable": true, "format": "date", "align": "center" }, + { "columnName": "item_code", "displayName": "품목코드", "order": 2, "visible": true, "sortable": true, "format": "text", "align": "left" }, + { "columnName": "item_name", "displayName": "품명", "order": 3, "visible": true, "sortable": true, "format": "text", "align": "left" }, + { "columnName": "plan_qty", "displayName": "계획수량", "order": 4, "visible": true, "sortable": true, "format": "number", "align": "right" }, + { "columnName": "start_date", "displayName": "시작일", "order": 5, "visible": true, "sortable": true, "format": "date", "align": "center" }, + { "columnName": "end_date", "displayName": "종료일", "order": 6, "visible": true, "sortable": true, "format": "date", "align": "center" }, + { "columnName": "due_date", "displayName": "납기일", "order": 7, "visible": true, "sortable": true, "format": "date", "align": "center" }, + { "columnName": "equipment_name", "displayName": "설비", "order": 8, "visible": true, "sortable": true, "format": "text", "align": "left" }, + { "columnName": "status", "displayName": "상태", "order": 9, "visible": true, "sortable": true, "format": "text", "align": "center" }, + { "columnName": "product_type", "displayName": "제품유형", "order": 10, "visible": true, "sortable": true, "format": "text", "align": "center" }, + { "columnName": "manager_name", "displayName": "담당자", "order": 11, "visible": true, "sortable": true, "format": "text", "align": "left" } + ], + "selectedTable": "production_plan_mng", + "pagination": { "enabled": true, "pageSize": 20, "pageSizeOptions": [10, 20, 50, 100] }, + "checkbox": { "enabled": true, "multiple": true }, + "horizontalScroll": { "enabled": true, "minColumnWidth": 80, "maxColumnWidth": 200 } + }, + "displayOrder": 1 + }, + { + "id": "comp_btn_register", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 100, "height": 40 }, + "position": { "x": 1580, "y": 70, "z": 1 }, + "overrides": { + "text": "신규 등록", + "type": "v2-button-primary", + "action": { "type": "modal", "modalTitle": "생산계획 등록", "targetScreenId": null }, + "variant": "success" + }, + "displayOrder": 2 + }, + { + "id": "comp_btn_edit", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 80, "height": 40 }, + "position": { "x": 1690, "y": 70, "z": 1 }, + "overrides": { + "text": "수정", + "type": "v2-button-primary", + "action": { "type": "edit", "modalTitle": "생산계획 수정", "targetScreenId": null }, + "variant": "secondary" + }, + "displayOrder": 3 + }, + { + "id": "comp_btn_delete", + "url": "@/lib/registry/components/v2-button-primary", + "size": { "width": 80, "height": 40 }, + "position": { "x": 1780, "y": 70, "z": 1 }, + "overrides": { + "text": "삭제", + "type": "v2-button-primary", + "action": { "type": "delete" }, + "variant": "danger" + }, + "displayOrder": 4 + } + ] +} +``` + +--- + +## 10. 구현 체크리스트 + +### 10.1 간소화 버전 (현재 구현 가능) + +| 체크 | 항목 | 설명 | +|:----:|------|------| +| ☐ | **테이블 생성** | `production_plan_mng` 테이블 생성 | +| ☐ | **화면 정의** | `screen_definitions` INSERT | +| ☐ | **모달 화면 생성** | 등록/수정 모달 화면 생성 | +| ☐ | **메인 화면 생성** | `screen_layouts_v2` INSERT | +| ☐ | **메뉴 연결** | 대상 메뉴에 화면 할당 | +| ☐ | **기본 CRUD 테스트** | 등록/수정/삭제/조회 테스트 | + +### 10.2 전체 버전 (향후 구현) + +| 체크 | 항목 | 설명 | +|:----:|------|------| +| ☐ | **v2-tabs 개발** | 탭 컴포넌트 개발 | +| ☐ | **v2-split-panel 개발** | 분할 패널 컴포넌트 개발 | +| ☐ | **v2-table-grouped 개발** | 그룹화 테이블 컴포넌트 개발 | +| ☐ | **v2-timeline-scheduler 개발** | 타임라인 스케줄러 개발 | +| ☐ | **자동 스케줄 로직** | 자동 스케줄 생성 백엔드 API | +| ☐ | **반제품 연동** | BOM 기반 반제품 계획 생성 | +| ☐ | **드래그&드롭** | 타임라인 드래그 이동 기능 | + +--- + +## 11. 관련 문서 + +- [수주관리](../02_sales/order.md) +- [품목정보](../01_master-data/item-info.md) +- [설비관리](../05_equipment/equipment-info.md) (예정) +- [BOM관리](../01_master-data/bom-info.md) (예정) diff --git a/docs/screen-implementation-guide/03_production/work-order.md b/docs/screen-implementation-guide/03_production/work-order.md new file mode 100644 index 00000000..47f3cd05 --- /dev/null +++ b/docs/screen-implementation-guide/03_production/work-order.md @@ -0,0 +1,194 @@ +# 작업지시 화면 구현 가이드 + +> **화면명**: 작업지시 +> **파일**: 작업지시.html +> **분류**: 생산관리 +> **구현 가능**: ⚠️ 부분 (그룹화 테이블 필요) + +--- + +## 1. 화면 개요 + +생산계획을 기반으로 작업지시를 생성하고 관리하는 화면입니다. + +### 핵심 기능 +- 작업지시 목록 조회 (탭별 구분) +- 그룹화 기능 (작업일자, 공정별) +- 작업지시 생성/수정/삭제 +- 작업지시서 인쇄 +- 실적 연계 + +--- + +## 2. 화면 레이아웃 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ [기간] [품목] [공정] [작업상태▼] [초기화][조회] [사용자옵션][엑셀] │ +├─────────────────────────────────────────────────────────────────┤ +│ [전체] [대기] [진행중] [완료] [지연] │ +├───────────────────────┬─────────────────────────────────────────┤ +│ 📋 작업지시 목록 │ 📄 작업지시 상세 │ +│ ─────────────── │ [인쇄] [시작] [완료] [수정] [삭제] │ +│ Group by: [작업일자▼] │ ───────────────────────── │ +│ ┌──────────────────┐ │ 지시번호: WO-2026-0001 │ +│ │▼ 2026-01-30 (5) │ │ 품목명: 제품A │ +│ │ WO-001|제품A|대기│ │ 지시수량: 100 EA │ +│ │ WO-002|제품B|진행│ ├─────────────────────────────────────────┤ +│ │▼ 2026-01-31 (3) │ │ [자재투입] [공정현황] [실적현황] │ +│ │ WO-003|제품C|대기│ │ ─────────────────────────── │ +│ └──────────────────┘ │ [투입자재 테이블] │ +└───────────────────────┴─────────────────────────────────────────┘ +``` + +--- + +## 3. V2 컴포넌트 매핑 + +| HTML 영역 | V2 컴포넌트 | 상태 | +|-----------|-------------|------| +| 검색 섹션 | `v2-table-search-widget` | ✅ 가능 | +| 상태 탭 | `v2-tabs-widget` | ✅ 가능 | +| 작업지시 목록 (그룹화) | `v2-table-list` | ⚠️ 그룹화 미지원 | +| 분할 패널 | `v2-split-panel-layout` | ✅ 가능 | +| 상세 탭 | `v2-tabs-widget` | ✅ 가능 | + +--- + +## 4. 테이블 정의 + +### 4.1 작업지시 목록 + +```typescript +columns: [ + { id: 'checkbox', type: 'checkbox', width: 50 }, + { id: 'work_order_no', label: '지시번호', width: 120 }, + { id: 'work_date', label: '작업일', width: 100 }, + { id: 'item_code', label: '품목코드', width: 100 }, + { id: 'item_name', label: '품목명', width: 200 }, + { id: 'order_qty', label: '지시수량', width: 100, align: 'right' }, + { id: 'prod_qty', label: '생산수량', width: 100, align: 'right' }, + { id: 'process_name', label: '공정', width: 100 }, + { id: 'status', label: '상태', width: 80 }, + { id: 'worker', label: '작업자', width: 100 } +] +``` + +### 4.2 자재투입 탭 + +```typescript +materialColumns: [ + { id: 'item_code', label: '품목코드', width: 100 }, + { id: 'item_name', label: '품목명', width: 200 }, + { id: 'required_qty', label: '소요량', width: 100, align: 'right' }, + { id: 'issued_qty', label: '투입량', width: 100, align: 'right' }, + { id: 'unit', label: '단위', width: 60 }, + { id: 'warehouse', label: '출고창고', width: 100 } +] +``` + +--- + +## 5. 상태 탭 + +```typescript +statusTabs: [ + { id: 'all', label: '전체', count: 25 }, + { id: 'waiting', label: '대기', count: 10 }, + { id: 'progress', label: '진행중', count: 8 }, + { id: 'completed', label: '완료', count: 5 }, + { id: 'delayed', label: '지연', count: 2 } +] +``` + +--- + +## 6. 그룹화 기능 (v2-grouped-table 필요) + +```typescript +groupByOptions: [ + { id: 'work_date', label: '작업일자' }, + { id: 'process_name', label: '공정' }, + { id: 'item_type', label: '품목구분' } +] +``` + +--- + +## 7. 현재 구현 가능 범위 + +### ✅ 가능 +- 검색 영역 +- 상태 탭 전환 +- 분할 패널 +- 상세 탭 +- 자재투입/공정현황/실적현황 테이블 + +### ⚠️ 부분 가능 +- 작업지시 목록: 그룹화 없이 일반 테이블 + +### ❌ 불가능 +- 동적 그룹화 + +--- + +## 8. 구현 JSON + +```json +{ + "screen_code": "WORK_ORDER_MAIN", + "screen_name": "작업지시", + "components": [ + { + "type": "v2-table-search-widget", + "position": { "x": 0, "y": 0, "w": 12, "h": 1 }, + "config": { + "searchFields": [ + { "type": "date", "id": "date_range", "placeholder": "기간", "dateRange": true }, + { "type": "input", "id": "item_name", "placeholder": "품목명" }, + { "type": "select", "id": "process", "placeholder": "공정" }, + { "type": "select", "id": "status", "placeholder": "상태" } + ] + } + }, + { + "type": "v2-tabs-widget", + "position": { "x": 0, "y": 1, "w": 12, "h": 11 }, + "config": { + "tabs": [ + { "id": "all", "label": "전체" }, + { "id": "waiting", "label": "대기" }, + { "id": "progress", "label": "진행중" }, + { "id": "completed", "label": "완료" }, + { "id": "delayed", "label": "지연" } + ], + "tabContent": { + "type": "v2-split-panel-layout", + "config": { + "masterPanel": { + "title": "작업지시 목록", + "entityId": "work_order", + "columns": [ + { "id": "work_order_no", "label": "지시번호" }, + { "id": "work_date", "label": "작업일" }, + { "id": "item_name", "label": "품목명" }, + { "id": "order_qty", "label": "지시수량" }, + { "id": "status", "label": "상태" } + ] + }, + "detailPanel": { + "tabs": [ + { "id": "material", "label": "자재투입", "entityId": "work_order_material" }, + { "id": "process", "label": "공정현황", "entityId": "work_order_process" }, + { "id": "result", "label": "실적현황", "entityId": "work_order_result" } + ] + } + } + } + } + } + ] +} +``` + +**v2-grouped-table 개발 시 재활용 가능** diff --git a/docs/screen-implementation-guide/04_purchase/.gitkeep b/docs/screen-implementation-guide/04_purchase/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/screen-implementation-guide/04_purchase/purchase-order.md b/docs/screen-implementation-guide/04_purchase/purchase-order.md new file mode 100644 index 00000000..225a331b --- /dev/null +++ b/docs/screen-implementation-guide/04_purchase/purchase-order.md @@ -0,0 +1,172 @@ +# 발주관리 화면 구현 가이드 + +> **화면명**: 발주관리 +> **파일**: 발주관리.html +> **분류**: 구매관리 +> **구현 가능**: ✅ 완전 (현재 V2 컴포넌트) + +--- + +## 1. 화면 개요 + +자재/원자재 발주를 생성하고 관리하는 화면입니다. + +### 핵심 기능 +- 발주 목록 조회/검색 +- 발주 등록/수정/삭제 +- 발주서 인쇄 +- 입고 연계 + +--- + +## 2. 화면 레이아웃 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ [기간] [공급업체] [발주번호] [품목명] [상태▼] [초기화][조회] │ +│ [사용자옵션][OCR][엑셀] │ +├─────────────────────────────────────────────────────────────────┤ +│ 📋 발주 목록 [신규등록] │ +│ ───────────────────────────────────────────────────────────── │ +│ │□|발주번호 |발주일 |공급업체 |발주금액 |상태 |담당자│ │ +│ │□|PO-2026..|2026-01-30|(주)원자재|5,000,000 |진행중|홍길동│ │ +│ │□|PO-2026..|2026-01-29|(주)부품사|3,200,000 |완료 |김철수│ │ +│ │□|PO-2026..|2026-01-28|(주)자재사|1,800,000 |진행중|이영희│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 3. V2 컴포넌트 매핑 + +| HTML 영역 | V2 컴포넌트 | 상태 | +|-----------|-------------|------| +| 검색 섹션 | `v2-table-search-widget` | ✅ 가능 | +| 발주 목록 | `v2-table-list` | ✅ 가능 | +| 발주 등록 모달 | `v2-modal-form` (필요) | ⚠️ 대체 가능 | + +--- + +## 4. 테이블 정의 + +```typescript +columns: [ + { id: 'checkbox', type: 'checkbox', width: 50 }, + { id: 'po_no', label: '발주번호', width: 120 }, + { id: 'po_date', label: '발주일', width: 100 }, + { id: 'supplier_name', label: '공급업체', width: 200 }, + { id: 'total_amount', label: '발주금액', width: 120, align: 'right', format: 'currency' }, + { id: 'delivery_date', label: '납기일', width: 100 }, + { id: 'status', label: '상태', width: 80 }, + { id: 'receive_status', label: '입고상태', width: 100 }, + { id: 'manager', label: '담당자', width: 100 } +] +``` + +--- + +## 5. 검색 조건 + +| 필드명 | 컴포넌트 | 설정 | +|--------|----------|------| +| 기간 | `v2-date` | dateRange: true | +| 공급업체 | `v2-input` | placeholder: "공급업체" | +| 발주번호 | `v2-input` | placeholder: "발주번호" | +| 품목명 | `v2-input` | placeholder: "품목명" | +| 상태 | `v2-select` | 작성중, 발주, 부분입고, 입고완료 | + +--- + +## 6. 구현 JSON + +```json +{ + "screen_code": "PO_MAIN", + "screen_name": "발주관리", + "components": [ + { + "type": "v2-table-search-widget", + "position": { "x": 0, "y": 0, "w": 12, "h": 2 }, + "config": { + "searchFields": [ + { "type": "date", "id": "date_range", "placeholder": "발주기간", "dateRange": true }, + { "type": "input", "id": "supplier_name", "placeholder": "공급업체" }, + { "type": "input", "id": "po_no", "placeholder": "발주번호" }, + { "type": "input", "id": "item_name", "placeholder": "품목명" }, + { "type": "select", "id": "status", "placeholder": "상태" } + ], + "buttons": [ + { "label": "초기화", "action": "reset", "variant": "outline" }, + { "label": "조회", "action": "search", "variant": "primary" } + ], + "rightButtons": [ + { "label": "사용자옵션", "action": "userOptions" }, + { "label": "OCR입력", "action": "ocr" }, + { "label": "엑셀다운로드", "action": "excelDownload" } + ] + } + }, + { + "type": "v2-table-list", + "position": { "x": 0, "y": 2, "w": 12, "h": 10 }, + "config": { + "title": "발주 목록", + "entityId": "purchase_order", + "buttons": [ + { "label": "신규등록", "action": "create", "variant": "primary" } + ], + "columns": [ + { "id": "po_no", "label": "발주번호", "width": 120 }, + { "id": "po_date", "label": "발주일", "width": 100 }, + { "id": "supplier_name", "label": "공급업체", "width": 200 }, + { "id": "total_amount", "label": "발주금액", "width": 120, "align": "right" }, + { "id": "delivery_date", "label": "납기일", "width": 100 }, + { "id": "status", "label": "상태", "width": 80 }, + { "id": "manager", "label": "담당자", "width": 100 } + ], + "rowActions": [ + { "label": "상세", "action": "view" }, + { "label": "수정", "action": "edit" }, + { "label": "삭제", "action": "delete" } + ] + } + } + ] +} +``` + +--- + +## 7. 데이터베이스 테이블 + +### purchase_order (발주 헤더) +```sql +CREATE TABLE purchase_order ( + id SERIAL PRIMARY KEY, + company_code VARCHAR(20) NOT NULL, + po_no VARCHAR(50) NOT NULL, + po_date DATE NOT NULL, + supplier_code VARCHAR(50), + supplier_name VARCHAR(200), + total_amount NUMERIC(15,2), + tax_amount NUMERIC(15,2), + status VARCHAR(20) DEFAULT 'draft', + delivery_date DATE, + manager VARCHAR(100), + remark TEXT, + created_at TIMESTAMPTZ DEFAULT NOW() +); +``` + +--- + +## 8. 구현 체크리스트 + +- [x] 검색 영역: v2-table-search-widget +- [x] 발주 목록 테이블: v2-table-list +- [x] 컬럼 정렬/필터 +- [ ] 발주 등록 모달 +- [ ] OCR 입력 기능 (별도) +- [ ] 인쇄 기능 + +**현재 V2 컴포넌트로 핵심 기능 구현 가능** diff --git a/docs/screen-implementation-guide/05_equipment/.gitkeep b/docs/screen-implementation-guide/05_equipment/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/screen-implementation-guide/05_equipment/equipment-info.md b/docs/screen-implementation-guide/05_equipment/equipment-info.md new file mode 100644 index 00000000..70405df8 --- /dev/null +++ b/docs/screen-implementation-guide/05_equipment/equipment-info.md @@ -0,0 +1,244 @@ +# 설비정보 화면 구현 가이드 + +> **화면명**: 설비정보 +> **파일**: 설비정보.html +> **분류**: 설비관리 +> **구현 가능**: ✅ 완전 (v2-card-display 활용) + +--- + +## 1. 화면 개요 + +생산 설비의 기본정보 및 상태를 관리하는 화면입니다. + +### 핵심 기능 +- 설비 목록 조회 (카드 형태) +- 설비 등록/수정/삭제 +- 설비 상세 정보 탭 관리 +- 설비 이미지 관리 + +--- + +## 2. 화면 레이아웃 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ [설비코드] [설비명] [설비유형▼] [상태▼] [초기화][조회] │ +│ [사용자옵션][업로드][다운로드]│ +├───────────────────────┬─────────────────────────────────────────┤ +│ 🏭 설비 목록 │ [기본정보][보전이력][점검이력][가동현황] │ +│ ─────────────── │ ───────────────────────────────────── │ +│ [신규등록] │ 설비코드: EQ-001 │ +│ ┌──────────────────┐ │ 설비명: CNC 밀링머신 1호기 │ +│ │ [이미지] EQ-001 │ │ 설비유형: 가공설비 │ +│ │ CNC 밀링 [가동중] │ │ 상태: 가동중 │ +│ ├──────────────────┤ │ 제조사: 현대공작기계 │ +│ │ [이미지] EQ-002 │ ├─────────────────────────────────────────┤ +│ │ 선반 1호 [점검중] │ │ [보전이력 테이블] │ +│ ├──────────────────┤ │ │일자 |유형 |내용 |담당자│ │ +│ │ [이미지] EQ-003 │ │ │2026-01|정기 |오일 교환 |김철수│ │ +│ │ 프레스 [고장] │ │ │2026-01|수리 |베어링 교체 |이영희│ │ +│ └──────────────────┘ │ │ +└───────────────────────┴─────────────────────────────────────────┘ +``` + +--- + +## 3. V2 컴포넌트 매핑 + +| HTML 영역 | V2 컴포넌트 | 상태 | +|-----------|-------------|------| +| 검색 섹션 | `v2-table-search-widget` | ✅ 가능 | +| 설비 카드 목록 | `v2-card-display` | ✅ 가능 | +| 분할 패널 | `v2-split-panel-layout` | ✅ 가능 | +| 상세 탭 | `v2-tabs-widget` | ✅ 가능 | + +--- + +## 4. 설비 카드 구조 + +```typescript +interface EquipmentCard { + id: string; + image: string; // 설비 이미지 URL + code: string; // 설비코드 + name: string; // 설비명 + type: string; // 설비유형 + status: 'running' | 'idle' | 'maintenance' | 'broken'; + location: string; +} + +// 상태별 스타일 +statusStyles: { + running: { bg: '#d1fae5', color: '#065f46', label: '가동중' }, + idle: { bg: '#e5e7eb', color: '#374151', label: '대기중' }, + maintenance: { bg: '#fef3c7', color: '#92400e', label: '점검중' }, + broken: { bg: '#fee2e2', color: '#991b1b', label: '고장' } +} +``` + +--- + +## 5. 상세 탭 구성 + +```typescript +tabs: [ + { + id: 'basic', + label: '기본정보', + fields: [ + { id: 'eq_code', label: '설비코드' }, + { id: 'eq_name', label: '설비명' }, + { id: 'eq_type', label: '설비유형' }, + { id: 'status', label: '상태' }, + { id: 'manufacturer', label: '제조사' }, + { id: 'model', label: '모델명' }, + { id: 'serial_no', label: '시리얼번호' }, + { id: 'install_date', label: '설치일' }, + { id: 'location', label: '설치위치' }, + { id: 'manager', label: '담당자' } + ] + }, + { + id: 'maintenance', + label: '보전이력', + type: 'table', + entityId: 'equipment_maintenance', + columns: [ + { id: 'date', label: '일자' }, + { id: 'type', label: '유형' }, + { id: 'content', label: '내용' }, + { id: 'worker', label: '담당자' }, + { id: 'cost', label: '비용' } + ] + }, + { + id: 'inspection', + label: '점검이력', + type: 'table', + entityId: 'equipment_inspection' + }, + { + id: 'operation', + label: '가동현황', + type: 'chart' // 향후 확장 + } +] +``` + +--- + +## 6. 검색 조건 + +| 필드명 | 컴포넌트 | 옵션 | +|--------|----------|------| +| 설비코드 | `v2-input` | placeholder: "설비코드" | +| 설비명 | `v2-input` | placeholder: "설비명" | +| 설비유형 | `v2-select` | 가공설비, 조립설비, 검사설비 등 | +| 상태 | `v2-select` | 가동중, 대기중, 점검중, 고장 | + +--- + +## 7. 현재 구현 가능 범위 + +### ✅ 가능 +- 검색 영역: `v2-table-search-widget` +- 설비 카드 목록: `v2-card-display` (이미지+정보 조합 지원) +- 분할 패널 레이아웃: `v2-split-panel-layout` +- 상세 탭: `v2-tabs-widget` +- 보전이력/점검이력 테이블: `v2-table-list` + +### ⚠️ 부분 가능 +- 가동현황 차트: 별도 차트 컴포넌트 필요 + +--- + +## 8. 테이블 대체 구현 JSON + +```json +{ + "screen_code": "EQUIPMENT_MAIN", + "screen_name": "설비정보", + "components": [ + { + "type": "v2-table-search-widget", + "position": { "x": 0, "y": 0, "w": 12, "h": 2 }, + "config": { + "searchFields": [ + { "type": "input", "id": "eq_code", "placeholder": "설비코드" }, + { "type": "input", "id": "eq_name", "placeholder": "설비명" }, + { "type": "select", "id": "eq_type", "placeholder": "설비유형" }, + { "type": "select", "id": "status", "placeholder": "상태", + "options": [ + { "value": "running", "label": "가동중" }, + { "value": "idle", "label": "대기중" }, + { "value": "maintenance", "label": "점검중" }, + { "value": "broken", "label": "고장" } + ] + } + ] + } + }, + { + "type": "v2-split-panel-layout", + "position": { "x": 0, "y": 2, "w": 12, "h": 10 }, + "config": { + "masterPanel": { + "title": "설비 목록", + "entityId": "equipment", + "buttons": [ + { "label": "신규등록", "action": "create", "variant": "primary" } + ], + "columns": [ + { "id": "eq_code", "label": "설비코드", "width": 100 }, + { "id": "eq_name", "label": "설비명", "width": 200 }, + { "id": "eq_type", "label": "설비유형", "width": 100 }, + { "id": "status", "label": "상태", "width": 80 }, + { "id": "location", "label": "설치위치", "width": 150 } + ] + }, + "detailPanel": { + "tabs": [ + { "id": "basic", "label": "기본정보", "type": "form" }, + { "id": "maintenance", "label": "보전이력", "type": "table", "entityId": "eq_maintenance" }, + { "id": "inspection", "label": "점검이력", "type": "table", "entityId": "eq_inspection" }, + { "id": "operation", "label": "가동현황", "type": "custom" } + ] + } + } + } + ] +} +``` + +--- + +## 9. v2-card-display 설정 예시 + +`v2-card-display`는 이미 존재하는 컴포넌트입니다. + +```typescript +// v2-card-display 설정 +cardDisplayConfig: { + cardsPerRow: 3, + cardSpacing: 16, + cardStyle: { + showTitle: true, // eq_name 표시 + showSubtitle: true, // eq_code 표시 + showDescription: true, + showImage: true, // 설비 이미지 표시 + showActions: true, + imagePosition: "top", + imageSize: "medium", + }, + columnMapping: { + title: "eq_name", + subtitle: "eq_code", + image: "image_url", + status: "status" + }, + dataSource: "table" +} +``` + +**현재 V2 컴포넌트로 완전 구현 가능** diff --git a/docs/screen-implementation-guide/06_logistics/.gitkeep b/docs/screen-implementation-guide/06_logistics/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/screen-implementation-guide/06_logistics/inout.md b/docs/screen-implementation-guide/06_logistics/inout.md new file mode 100644 index 00000000..943e07a4 --- /dev/null +++ b/docs/screen-implementation-guide/06_logistics/inout.md @@ -0,0 +1,179 @@ +# 입출고관리 화면 구현 가이드 + +> **화면명**: 입출고관리 +> **파일**: 입출고관리.html +> **분류**: 물류관리 +> **구현 가능**: ⚠️ 부분 (그룹화 테이블 필요) + +--- + +## 1. 화면 개요 + +자재/제품의 입고 및 출고 내역을 통합 관리하는 화면입니다. + +### 핵심 기능 +- 입출고 내역 조회/검색 +- 그룹화 기능 (입출고구분, 창고, 카테고리별) +- 엑셀 업로드/다운로드 + +--- + +## 2. 화면 레이아웃 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ [입출고구분▼][카테고리▼][창고▼][품목코드][품목명][기간][초기화][검색]│ +│ [사용자옵션][업로드][다운로드]│ +├─────────────────────────────────────────────────────────────────┤ +│ 📋 입출고 내역 전체 150건 │ +│ ───────────────────────────────────────────────────────────── │ +│ Group by: [입출고구분▼] │ +│ ───────────────────────────────────────────────────────────── │ +│ │▼ 입고 (80) │ +│ │ │IN-001|구매입고|2026-01-30|본사창고|P-001|원자재A|100|KG │ +│ │ │IN-002|생산입고|2026-01-30|제1창고|P-002|제품A |50 |EA │ +│ │▼ 출고 (70) │ +│ │ │OUT-001|판매출고|2026-01-30|본사창고|P-003|제품B|30|EA │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 3. V2 컴포넌트 매핑 + +| HTML 영역 | V2 컴포넌트 | 상태 | +|-----------|-------------|------| +| 검색 섹션 | `v2-table-search-widget` | ✅ 가능 | +| 입출고 목록 (그룹화) | `v2-table-list` | ⚠️ 그룹화 미지원 | + +--- + +## 4. 테이블 정의 + +```typescript +columns: [ + { id: 'checkbox', type: 'checkbox', width: 50 }, + { id: 'inout_type', label: '입출고구분', width: 100 }, + { id: 'category', label: '카테고리', width: 120 }, + { id: 'doc_no', label: '전표번호', width: 120 }, + { id: 'process_date', label: '처리일자', width: 100 }, + { id: 'warehouse', label: '창고', width: 120 }, + { id: 'location', label: '위치', width: 100 }, + { id: 'item_code', label: '품목코드', width: 120 }, + { id: 'item_name', label: '품목명', width: 200 }, + { id: 'quantity', label: '수량', width: 100, align: 'right' }, + { id: 'unit', label: '단위', width: 60 }, + { id: 'lot_no', label: '로트번호', width: 120 }, + { id: 'customer', label: '거래처', width: 120 }, + { id: 'manager', label: '담당자', width: 100 }, + { id: 'remark', label: '비고', width: 200 } +] +``` + +--- + +## 5. 검색 조건 + +| 필드명 | 컴포넌트 | 옵션 | +|--------|----------|------| +| 입출고구분 | `v2-select` | 입고, 출고 | +| 카테고리 | `v2-select` | 구매입고, 생산입고, 반품입고, 판매출고, 생산출고 등 | +| 창고 | `v2-select` | 본사창고, 제1창고, 제2창고 | +| 품목코드 | `v2-input` | - | +| 품목명 | `v2-input` | - | +| 기간 | `v2-date` | dateRange: true | + +--- + +## 6. 그룹화 기능 (v2-grouped-table 필요) + +```typescript +groupByOptions: [ + { id: 'inout_type', label: '입출고구분' }, + { id: 'category', label: '카테고리' }, + { id: 'warehouse', label: '창고' }, + { id: 'item_code', label: '품목코드' }, + { id: 'process_date', label: '처리일자' }, + { id: 'customer', label: '거래처' } +] +``` + +--- + +## 7. 현재 구현 가능 범위 + +### ✅ 가능 +- 검색 영역 +- 일반 테이블 목록 + +### ⚠️ 부분 가능 +- 그룹화 없이 필터로 대체 + +### ❌ 불가능 +- 동적 그룹화 + +--- + +## 8. 간소화 구현 JSON + +```json +{ + "screen_code": "INOUT_MAIN", + "screen_name": "입출고관리", + "components": [ + { + "type": "v2-table-search-widget", + "position": { "x": 0, "y": 0, "w": 12, "h": 2 }, + "config": { + "searchFields": [ + { "type": "select", "id": "inout_type", "placeholder": "입출고구분", + "options": [ + { "value": "IN", "label": "입고" }, + { "value": "OUT", "label": "출고" } + ] + }, + { "type": "select", "id": "category", "placeholder": "카테고리", + "options": [ + { "value": "purchase", "label": "구매입고" }, + { "value": "production_in", "label": "생산입고" }, + { "value": "return_in", "label": "반품입고" }, + { "value": "sales", "label": "판매출고" }, + { "value": "production_out", "label": "생산출고" } + ] + }, + { "type": "select", "id": "warehouse", "placeholder": "창고" }, + { "type": "input", "id": "item_code", "placeholder": "품목코드" }, + { "type": "input", "id": "item_name", "placeholder": "품목명" }, + { "type": "date", "id": "date_range", "placeholder": "처리일자", "dateRange": true } + ], + "buttons": [ + { "label": "초기화", "action": "reset" }, + { "label": "검색", "action": "search", "variant": "primary" } + ] + } + }, + { + "type": "v2-table-list", + "position": { "x": 0, "y": 2, "w": 12, "h": 10 }, + "config": { + "title": "입출고 내역", + "entityId": "inventory_transaction", + "showTotalCount": true, + "columns": [ + { "id": "inout_type", "label": "입출고구분", "width": 100 }, + { "id": "category", "label": "카테고리", "width": 120 }, + { "id": "doc_no", "label": "전표번호", "width": 120 }, + { "id": "process_date", "label": "처리일자", "width": 100 }, + { "id": "warehouse", "label": "창고", "width": 120 }, + { "id": "item_code", "label": "품목코드", "width": 120 }, + { "id": "item_name", "label": "품목명", "width": 200 }, + { "id": "quantity", "label": "수량", "width": 100, "align": "right" }, + { "id": "unit", "label": "단위", "width": 60 } + ] + } + } + ] +} +``` + +**v2-grouped-table 개발 시 그룹화 기능 추가 가능** diff --git a/docs/screen-implementation-guide/07_quality/.gitkeep b/docs/screen-implementation-guide/07_quality/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/screen-implementation-guide/07_quality/inspection.md b/docs/screen-implementation-guide/07_quality/inspection.md new file mode 100644 index 00000000..a2fdc95d --- /dev/null +++ b/docs/screen-implementation-guide/07_quality/inspection.md @@ -0,0 +1,169 @@ +# 검사정보관리 화면 구현 가이드 + +> **화면명**: 검사정보관리 +> **파일**: 검사정보관리.html +> **분류**: 품질관리 +> **구현 가능**: ✅ 완전 (현재 V2 컴포넌트) + +--- + +## 1. 화면 개요 + +품질 검사 결과를 등록하고 관리하는 화면입니다. + +### 핵심 기능 +- 검사 유형별 탭 (수입검사, 공정검사, 출하검사) +- 검사 결과 등록/수정 +- 불량 처리 연계 +- 검사 이력 관리 + +--- + +## 2. 화면 레이아웃 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ [기간] [품목] [거래처] [검사결과▼] [초기화][조회] [사용자옵션][엑셀]│ +├─────────────────────────────────────────────────────────────────┤ +│ [🔍수입검사(25)][⚙️공정검사(18)][📦출하검사(12)] │ +├─────────────────────────────────────────────────────────────────┤ +│ 📋 수입검사 목록 [신규등록] │ +│ ───────────────────────────────────────────────────────────── │ +│ │□|검사번호 |검사일 |품목명 |검사수량|합격수량|불량수량|결과│ +│ │□|IQC-001 |2026-01-30|원자재A |100 |98 |2 |합격│ +│ │□|IQC-002 |2026-01-30|원자재B |200 |195 |5 |합격│ +│ │□|IQC-003 |2026-01-29|부품C |50 |30 |20 |불합격│ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 3. V2 컴포넌트 매핑 + +| HTML 영역 | V2 컴포넌트 | 상태 | +|-----------|-------------|------| +| 검색 섹션 | `v2-table-search-widget` | ✅ 가능 | +| 검사유형 탭 | `v2-tabs-widget` | ✅ 가능 | +| 검사 목록 | `v2-table-list` | ✅ 가능 | + +--- + +## 4. 탭 구성 + +```typescript +tabs: [ + { id: 'incoming', label: '수입검사', icon: '🔍', count: 25 }, + { id: 'process', label: '공정검사', icon: '⚙️', count: 18 }, + { id: 'shipping', label: '출하검사', icon: '📦', count: 12 } +] +``` + +--- + +## 5. 테이블 정의 + +```typescript +columns: [ + { id: 'checkbox', type: 'checkbox', width: 50 }, + { id: 'inspect_no', label: '검사번호', width: 120 }, + { id: 'inspect_date', label: '검사일', width: 100 }, + { id: 'item_code', label: '품목코드', width: 100 }, + { id: 'item_name', label: '품목명', width: 200 }, + { id: 'lot_no', label: '로트번호', width: 120 }, + { id: 'inspect_qty', label: '검사수량', width: 100, align: 'right' }, + { id: 'pass_qty', label: '합격수량', width: 100, align: 'right' }, + { id: 'fail_qty', label: '불량수량', width: 100, align: 'right' }, + { id: 'result', label: '결과', width: 80 }, + { id: 'inspector', label: '검사자', width: 100 } +] +``` + +--- + +## 6. 검색 조건 + +| 필드명 | 컴포넌트 | 설정 | +|--------|----------|------| +| 기간 | `v2-date` | dateRange: true | +| 품목 | `v2-input` | placeholder: "품목" | +| 거래처 | `v2-input` | placeholder: "거래처" | +| 검사결과 | `v2-select` | 전체, 합격, 불합격, 조건부합격 | + +--- + +## 7. 구현 JSON + +```json +{ + "screen_code": "INSPECTION_MAIN", + "screen_name": "검사정보관리", + "components": [ + { + "type": "v2-table-search-widget", + "position": { "x": 0, "y": 0, "w": 12, "h": 2 }, + "config": { + "searchFields": [ + { "type": "date", "id": "date_range", "placeholder": "검사기간", "dateRange": true }, + { "type": "input", "id": "item_name", "placeholder": "품목" }, + { "type": "input", "id": "supplier", "placeholder": "거래처" }, + { "type": "select", "id": "result", "placeholder": "검사결과", + "options": [ + { "value": "pass", "label": "합격" }, + { "value": "fail", "label": "불합격" }, + { "value": "conditional", "label": "조건부합격" } + ] + } + ], + "buttons": [ + { "label": "초기화", "action": "reset" }, + { "label": "조회", "action": "search", "variant": "primary" } + ] + } + }, + { + "type": "v2-tabs-widget", + "position": { "x": 0, "y": 2, "w": 12, "h": 10 }, + "config": { + "tabs": [ + { "id": "incoming", "label": "수입검사" }, + { "id": "process", "label": "공정검사" }, + { "id": "shipping", "label": "출하검사" } + ], + "tabContent": { + "type": "v2-table-list", + "config": { + "entityId": "inspection", + "filterByTab": true, + "tabFilterField": "inspect_type", + "buttons": [ + { "label": "신규등록", "action": "create", "variant": "primary" } + ], + "columns": [ + { "id": "inspect_no", "label": "검사번호", "width": 120 }, + { "id": "inspect_date", "label": "검사일", "width": 100 }, + { "id": "item_name", "label": "품목명", "width": 200 }, + { "id": "lot_no", "label": "로트번호", "width": 120 }, + { "id": "inspect_qty", "label": "검사수량", "width": 100 }, + { "id": "pass_qty", "label": "합격수량", "width": 100 }, + { "id": "fail_qty", "label": "불량수량", "width": 100 }, + { "id": "result", "label": "결과", "width": 80 } + ] + } + } + } + } + ] +} +``` + +--- + +## 8. 구현 체크리스트 + +- [x] 검색 영역: v2-table-search-widget +- [x] 검사유형 탭: v2-tabs-widget +- [x] 검사 목록 테이블: v2-table-list +- [ ] 검사 등록 모달 +- [ ] 불량 처리 연계 + +**현재 V2 컴포넌트로 핵심 기능 구현 가능** diff --git a/docs/screen-implementation-guide/README.md b/docs/screen-implementation-guide/README.md index 18acd6db..f82a1fda 100644 --- a/docs/screen-implementation-guide/README.md +++ b/docs/screen-implementation-guide/README.md @@ -2,56 +2,89 @@ V2 컴포넌트를 활용한 ERP 화면 구현 가이드입니다. +--- + +## 전체 화면 분석 요약 (2026-01-30) + +### 컴포넌트 커버리지 + +| 구분 | 화면 수 | 비율 | +|------|--------|------| +| 현재 즉시 구현 가능 | 17개 | 65% | +| v2-grouped-table 추가 시 | 22개 | 85% | +| v2-tree-view 추가 시 | 24개 | 92% | +| 별도 개발 필요 | 2개 | 8% | + +### 신규 컴포넌트 개발 우선순위 + +| 순위 | 컴포넌트 | 재활용 화면 수 | ROI | +|------|----------|--------------|-----| +| 1 | v2-grouped-table | 5+ | 높음 | +| 2 | v2-tree-view | 3 | 중간 | +| 3 | v2-timeline-scheduler | 1~2 | 낮음 | + +> **참고**: 화면 디자이너에서 폼 배치가 자체 규격으로 처리되므로 별도 모달/폼 컴포넌트 불필요. +> `v2-card-display`는 이미 존재합니다. + +> 상세 분석: [full-screen-analysis.md](./00_analysis/full-screen-analysis.md) + +--- + ## 폴더 구조 ``` screen-implementation-guide/ +├── 00_analysis/ # 전체 분석 +│ └── full-screen-analysis.md # 화면 전체 분석 보고서 +│ ├── 01_master-data/ # 기준정보 +│ ├── item-info.md # 품목정보 ✅ +│ ├── bom.md # BOM관리 ⚠️ │ ├── company-info.md # 회사정보 │ ├── department.md # 부서관리 -│ ├── item-info.md # 품목정보 │ └── options.md # 옵션설정 │ ├── 02_sales/ # 영업관리 -│ ├── quotation.md # 견적관리 -│ ├── order.md # 수주관리 -│ ├── customer.md # 거래처관리 +│ ├── order.md # 수주관리 ✅ +│ ├── quote.md # 견적관리 ✅ +│ ├── customer.md # 거래처관리 ⚠️ │ ├── sales-item.md # 판매품목정보 │ └── options.md # 영업옵션설정 │ ├── 03_production/ # 생산관리 -│ ├── production-plan.md # 생산계획 -│ ├── work-order.md # 작업지시 +│ ├── production-plan.md # 생산계획관리 ❌ +│ ├── work-order.md # 작업지시 ⚠️ │ ├── production-result.md # 생산실적 │ ├── process-info.md # 공정정보관리 -│ ├── bom.md # BOM관리 │ └── options.md # 생산옵션설정 │ ├── 04_purchase/ # 구매관리 -│ ├── purchase-order.md # 발주관리 +│ ├── purchase-order.md # 발주관리 ✅ │ ├── purchase-item.md # 구매품목정보 │ ├── supplier.md # 공급업체관리 │ ├── receiving.md # 입고관리 │ └── options.md # 구매옵션설정 │ ├── 05_equipment/ # 설비관리 -│ ├── equipment-info.md # 설비정보 +│ ├── equipment-info.md # 설비정보 ✅ │ └── options.md # 설비옵션설정 │ ├── 06_logistics/ # 물류관리 +│ ├── inout.md # 입출고관리 ⚠️ │ ├── logistics-info.md # 물류정보관리 -│ ├── inout.md # 입출고관리 │ ├── inventory.md # 재고현황 │ ├── warehouse.md # 창고정보관리 │ ├── shipping.md # 출고관리 │ └── options.md # 물류옵션설정 │ ├── 07_quality/ # 품질관리 -│ ├── inspection-info.md # 검사정보관리 +│ ├── inspection.md # 검사정보관리 ✅ │ ├── item-inspection.md # 품목검사정보 │ └── options.md # 품질옵션설정 │ └── README.md + +# 범례: ✅ 완전구현 | ⚠️ 부분구현 | ❌ 신규개발필요 ``` ## 문서 작성 형식 diff --git a/docs/screen-implementation-guide/SCREEN_DEVELOPMENT_STANDARD.md b/docs/screen-implementation-guide/SCREEN_DEVELOPMENT_STANDARD.md new file mode 100644 index 00000000..606caa03 --- /dev/null +++ b/docs/screen-implementation-guide/SCREEN_DEVELOPMENT_STANDARD.md @@ -0,0 +1,572 @@ +# Screen Development Standard Guide (AI Agent Reference) + +> **Purpose**: Ensure consistent screen development output regardless of who develops it +> **Target**: AI Agents (Cursor, etc.), Developers +> **Version**: 1.0.0 + +--- + +## CRITICAL RULES + +1. **ONLY use V2 components** (components with `v2-` prefix) +2. **SEPARATE UI and Logic**: UI in `screen_layouts_v2`, Logic in `dataflow_diagrams` +3. **ALWAYS apply company_code filtering** (multi-tenancy) + +--- + +## AVAILABLE V2 COMPONENTS (23 total) + +### Input Components +| ID | Name | Purpose | +|----|------|---------| +| `v2-input` | Input | text, number, password, email, tel, url, textarea | +| `v2-select` | Select | dropdown, combobox, radio, checkbox | +| `v2-date` | Date | date, time, datetime, daterange, month, year | + +### Display Components +| ID | Name | Purpose | +|----|------|---------| +| `v2-text-display` | Text Display | labels, titles | +| `v2-card-display` | Card Display | table data as cards | +| `v2-aggregation-widget` | Aggregation Widget | sum, avg, count, min, max | + +### Table/Data Components +| ID | Name | Purpose | +|----|------|---------| +| `v2-table-list` | Table List | data grid with CRUD | +| `v2-table-search-widget` | Search Widget | table search/filter | +| `v2-pivot-grid` | Pivot Grid | multi-dimensional analysis | + +### Layout Components +| ID | Name | Purpose | +|----|------|---------| +| `v2-split-panel-layout` | Split Panel | master-detail layout | +| `v2-tabs-widget` | Tabs Widget | tab navigation | +| `v2-section-card` | Section Card | titled grouping container | +| `v2-section-paper` | Section Paper | background grouping | +| `v2-divider-line` | Divider | area separator | +| `v2-repeat-container` | Repeat Container | data-driven repeat | +| `v2-repeater` | Repeater | repeat control | +| `v2-repeat-screen-modal` | Repeat Screen Modal | modal repeat | + +### Action/Special Components +| ID | Name | Purpose | +|----|------|---------| +| `v2-button-primary` | Primary Button | save, delete, etc. | +| `v2-numbering-rule` | Numbering Rule | auto code generation | +| `v2-category-manager` | Category Manager | category management | +| `v2-location-swap-selector` | Location Swap | location selection | +| `v2-rack-structure` | Rack Structure | warehouse rack visualization | +| `v2-media` | Media | image/video display | + +--- + +## SCREEN PATTERNS (5 types) + +### Pattern A: Basic Master Screen +**When**: Single table CRUD +**Components**: +``` +v2-table-search-widget +v2-table-list +v2-button-primary +``` + +### Pattern B: Master-Detail Screen +**When**: Master selection → Detail display +**Components**: +``` +v2-split-panel-layout + ├─ left: v2-table-list (master) + └─ right: v2-table-list (detail) +``` +**Required Config**: +```json +{ + "leftPanel": { "tableName": "master_table" }, + "rightPanel": { + "tableName": "detail_table", + "relation": { "type": "detail", "foreignKey": "master_id" } + }, + "splitRatio": 30 +} +``` + +### Pattern C: Master-Detail + Tabs +**When**: Master selection → Multiple tabs +**Components**: +``` +v2-split-panel-layout + ├─ left: v2-table-list (master) + └─ right: v2-tabs-widget +``` + +### Pattern D: Card View +**When**: Image + info card display +**Components**: +``` +v2-table-search-widget +v2-card-display +``` +**Required Config**: +```json +{ + "cardsPerRow": 3, + "columnMapping": { + "title": "name", + "subtitle": "code", + "image": "image_url" + } +} +``` + +### Pattern E: Pivot Analysis +**When**: Multi-dimensional aggregation +**Components**: +``` +v2-pivot-grid +``` + +--- + +## DATABASE TABLES + +### Screen Definition +```sql +-- screen_definitions: Screen basic info +INSERT INTO screen_definitions ( + screen_name, screen_code, description, table_name, company_code +) VALUES (...) RETURNING screen_id; + +-- screen_layouts_v2: UI layout (JSON) +INSERT INTO screen_layouts_v2 ( + screen_id, company_code, layout_data +) VALUES (...); + +-- screen_menu_assignments: Menu connection +INSERT INTO screen_menu_assignments ( + screen_id, menu_objid, company_code +) VALUES (...); +``` + +### Control Management (Business Logic) +```sql +-- dataflow_diagrams: Business logic +INSERT INTO dataflow_diagrams ( + diagram_name, company_code, control, plan +) VALUES (...); +``` + +--- + +## UI SETTING vs BUSINESS LOGIC + +### UI Setting (Screen Designer) +| Item | Storage | +|------|---------| +| Component placement | screen_layouts_v2.layout_data | +| Table name | layout_data.tableName | +| Column visibility | layout_data.columns | +| Search fields | layout_data.searchFields | +| Basic save/delete | button config.action.type | + +### Business Logic (Control Management) +| Item | Storage | +|------|---------| +| Conditional execution | dataflow_diagrams.control | +| Multi-table save | dataflow_diagrams.plan | +| Before/after trigger | control.triggerType | +| Field mapping | plan.mappings | + +--- + +## BUSINESS LOGIC JSON STRUCTURE + +### Control (Conditions) +```json +{ + "control": { + "actionType": "update|insert|delete", + "triggerType": "before|after", + "conditions": [ + { + "id": "unique-id", + "type": "condition", + "field": "column_name", + "operator": "=|!=|>|<|>=|<=|LIKE|IN|IS NULL", + "value": "compare_value", + "dataType": "string|number|date|boolean" + } + ] + } +} +``` + +### Plan (Actions) +```json +{ + "plan": { + "actions": [ + { + "id": "action-id", + "actionType": "update|insert|delete", + "targetTable": "table_name", + "fieldMappings": [ + { + "sourceField": "source_column", + "targetField": "target_column", + "defaultValue": "static_value", + "valueType": "field|static" + } + ] + } + ] + } +} +``` + +### Special Values +| Value | Meaning | +|-------|---------| +| `#NOW` | Current timestamp | +| `#USER` | Current user ID | +| `#COMPANY` | Current company code | + +--- + +## DEVELOPMENT STEPS + +### Step 1: Analyze Requirements +``` +1. Which tables? (table names) +2. Table relationships? (FK) +3. Which pattern? (A/B/C/D/E) +4. Which buttons? +5. Business logic per button? +``` + +### Step 2: INSERT screen_definitions +```sql +INSERT INTO screen_definitions ( + screen_name, screen_code, description, table_name, company_code, created_at +) VALUES ( + '화면명', 'SCREEN_CODE', '설명', 'main_table', 'COMPANY_CODE', NOW() +) RETURNING screen_id; +``` + +### Step 3: INSERT screen_layouts_v2 +```sql +INSERT INTO screen_layouts_v2 ( + screen_id, company_code, layout_data +) VALUES ( + {screen_id}, 'COMPANY_CODE', '{layout_json}'::jsonb +); +``` + +### Step 4: INSERT dataflow_diagrams (if complex logic) +```sql +INSERT INTO dataflow_diagrams ( + diagram_name, company_code, control, plan +) VALUES ( + '화면명_제어', 'COMPANY_CODE', '{control_json}'::jsonb, '{plan_json}'::jsonb +) RETURNING diagram_id; +``` + +### Step 5: Link button to dataflow +In layout_data, set button config: +```json +{ + "id": "btn-action", + "componentType": "v2-button-primary", + "componentConfig": { + "text": "확정", + "enableDataflowControl": true, + "dataflowDiagramId": {diagram_id} + } +} +``` + +### Step 6: INSERT screen_menu_assignments +```sql +INSERT INTO screen_menu_assignments ( + screen_id, menu_objid, company_code +) VALUES ( + {screen_id}, {menu_objid}, 'COMPANY_CODE' +); +``` + +--- + +## EXAMPLE: Order Management + +### Requirements +``` +Screen: 수주관리 (Order Management) +Pattern: B (Master-Detail) +Tables: + - Master: order_master + - Detail: order_detail +Buttons: + - [저장]: Save to order_master + - [확정]: + - Condition: status = '대기' + - Action: Update status to '확정' + - Additional: Insert to order_history +``` + +### layout_data JSON +```json +{ + "components": [ + { + "id": "search-1", + "componentType": "v2-table-search-widget", + "position": {"x": 0, "y": 0}, + "size": {"width": 1920, "height": 80} + }, + { + "id": "split-1", + "componentType": "v2-split-panel-layout", + "position": {"x": 0, "y": 80}, + "size": {"width": 1920, "height": 800}, + "componentConfig": { + "leftPanel": {"tableName": "order_master"}, + "rightPanel": { + "tableName": "order_detail", + "relation": {"type": "detail", "foreignKey": "order_id"} + }, + "splitRatio": 30 + } + }, + { + "id": "btn-save", + "componentType": "v2-button-primary", + "componentConfig": { + "text": "저장", + "action": {"type": "save"} + } + }, + { + "id": "btn-confirm", + "componentType": "v2-button-primary", + "componentConfig": { + "text": "확정", + "enableDataflowControl": true, + "dataflowDiagramId": 123 + } + } + ] +} +``` + +### dataflow_diagrams JSON (for 확정 button) +```json +{ + "control": { + "actionType": "update", + "triggerType": "after", + "conditions": [ + { + "id": "cond-1", + "type": "condition", + "field": "status", + "operator": "=", + "value": "대기", + "dataType": "string" + } + ] + }, + "plan": { + "actions": [ + { + "id": "action-1", + "actionType": "update", + "targetTable": "order_master", + "fieldMappings": [ + {"targetField": "status", "defaultValue": "확정"} + ] + }, + { + "id": "action-2", + "actionType": "insert", + "targetTable": "order_history", + "fieldMappings": [ + {"sourceField": "order_no", "targetField": "order_no"}, + {"sourceField": "customer_name", "targetField": "customer_name"}, + {"defaultValue": "#NOW", "targetField": "confirmed_at"} + ] + } + ] + } +} +``` + +--- + +## NOT SUPPORTED (Requires Custom Development) + +| UI Type | Status | Alternative | +|---------|--------|-------------| +| Tree View | ❌ | Develop `v2-tree-view` | +| Grouped Table | ❌ | Develop `v2-grouped-table` | +| Gantt Chart | ❌ | Separate development | +| Drag & Drop | ❌ | Use order column | + +--- + +## CHECKLIST + +### Screen Creation +``` +□ screen_definitions INSERT completed +□ screen_layouts_v2 INSERT completed +□ screen_menu_assignments INSERT completed (if needed) +□ company_code filtering applied +□ All components have v2- prefix +``` + +### Business Logic +``` +□ Basic actions (save/delete) → Screen designer setting +□ Conditional/Multi-table → dataflow_diagrams INSERT +□ Button config has dataflowDiagramId +□ control.conditions configured +□ plan.actions or plan.mappings configured +``` + +--- + +## BUSINESS LOGIC REQUEST FORMAT (MANDATORY) + +> **WARNING**: No format = No processing. Write it properly, idiot. +> Vague input = vague output. No input = no output. + +### Request Template + +``` +=== BUSINESS LOGIC REQUEST === + +【SCREEN INFO】 +- Screen Name: +- Company Code: +- Menu ID (if any): + +【TABLE INFO】 +- Main Table: +- Detail Table (if any): +- FK Relation (if any): + +【BUTTON LIST】 +Button 1: + - Name: + - Action Type: (save/delete/update/query/other) + - Condition (if any): + - Target Table: + - Additional Actions (if any): + +Button 2: + - Name: + - ... + +【ADDITIONAL REQUIREMENTS】 +- +``` + +### Valid Example + +``` +=== BUSINESS LOGIC REQUEST === + +【SCREEN INFO】 +- Screen Name: 수주관리 (Order Management) +- Company Code: ssalmeog +- Menu ID: 55566 + +【TABLE INFO】 +- Main Table: order_master +- Detail Table: order_detail +- FK Relation: order_id + +【BUTTON LIST】 +Button 1: + - Name: 저장 (Save) + - Action Type: save + - Condition: none + - Target Table: order_master, order_detail + - Additional Actions: none + +Button 2: + - Name: 확정 (Confirm) + - Action Type: update + - Condition: status = '대기' + - Target Table: order_master + - Additional Actions: + 1. Change status to '확정' + 2. INSERT to order_history (order_no, customer_name, confirmed_at=NOW) + +Button 3: + - Name: 삭제 (Delete) + - Action Type: delete + - Condition: status != '확정' + - Target Table: order_master, order_detail (cascade) + - Additional Actions: none + +【ADDITIONAL REQUIREMENTS】 +- Confirmed orders cannot be modified/deleted +- Auto-numbering for order_no (ORDER-YYYYMMDD-0001) +``` + +### Invalid Examples (DO NOT DO THIS) + +``` +❌ "Make an order management screen" + → Which table? Buttons? Logic? + +❌ "Save button should save" + → To which table? Conditions? + +❌ "Handle inventory when confirmed" + → Which table? Increase? Decrease? By how much? + +❌ "Similar to the previous screen" + → What previous screen? +``` + +### Complex Logic Format + +For multiple conditions or complex workflows: + +``` +【COMPLEX BUTTON LOGIC】 +Button Name: 출고확정 (Shipment Confirm) + +Execution Conditions: + Cond1: status = '출고대기' AND + Cond2: qty > 0 AND + Cond3: warehouse_id IS NOT NULL + +Execution Steps (in order): + 1. shipment_master.status → '출고완료' + 2. Decrease qty in inventory (WHERE item_code = current_row.item_code) + 3. INSERT to shipment_history: + - shipment_no ← current_row.shipment_no + - shipped_qty ← current_row.qty + - shipped_at ← #NOW + - shipped_by ← #USER + +On Failure: + - Insufficient stock: Show "재고가 부족합니다" + - Condition not met: Show "출고대기 상태만 확정 가능합니다" +``` + +--- + +## REFERENCE PATHS + +| Item | Path/Table | +|------|------------| +| Control Management Page | `/admin/systemMng/dataflow` | +| Screen Definition Table | `screen_definitions` | +| Layout Table | `screen_layouts_v2` | +| Control Table | `dataflow_diagrams` | +| Menu Assignment Table | `screen_menu_assignments` | diff --git a/docs/screen-implementation-guide/화면개발_표준_가이드.md b/docs/screen-implementation-guide/화면개발_표준_가이드.md new file mode 100644 index 00000000..83774f38 --- /dev/null +++ b/docs/screen-implementation-guide/화면개발_표준_가이드.md @@ -0,0 +1,706 @@ +# 화면 개발 표준 가이드 + +> **목적**: 어떤 개발자/AI가 화면을 개발하든 동일한 결과물이 나오도록 하는 표준 가이드 +> **대상**: 개발자, AI 에이전트 (Cursor 등) +> **버전**: 1.0.0 + +--- + +## 1. 개요 + +이 문서는 WACE 솔루션에서 화면을 개발할 때 반드시 따라야 하는 표준입니다. +비즈니스 로직을 어떻게 설명하든, 최종 결과물은 이 가이드대로 생성되어야 합니다. + +### 핵심 원칙 + +1. **V2 컴포넌트만 사용**: `v2-` 접두사가 붙은 컴포넌트만 사용 +2. **UI와 로직 분리**: UI는 `screen_layouts_v2`, 비즈니스 로직은 `dataflow_diagrams` +3. **멀티테넌시 필수**: 모든 쿼리에 `company_code` 필터링 + +--- + +## 2. 사용 가능한 V2 컴포넌트 목록 (23개) + +### 입력 컴포넌트 + +| ID | 이름 | 용도 | +|----|------|------| +| `v2-input` | 입력 | 텍스트, 숫자, 비밀번호, 이메일 등 | +| `v2-select` | 선택 | 드롭다운, 콤보박스, 라디오, 체크박스 | +| `v2-date` | 날짜 | 날짜, 시간, 날짜범위 | + +### 표시 컴포넌트 + +| ID | 이름 | 용도 | +|----|------|------| +| `v2-text-display` | 텍스트 표시 | 라벨, 제목 | +| `v2-card-display` | 카드 디스플레이 | 테이블 데이터를 카드 형태로 표시 | +| `v2-aggregation-widget` | 집계 위젯 | 합계, 평균, 개수 등 | + +### 테이블/데이터 컴포넌트 + +| ID | 이름 | 용도 | +|----|------|------| +| `v2-table-list` | 테이블 리스트 | 데이터 조회/편집 테이블 | +| `v2-table-search-widget` | 검색 필터 | 테이블 검색/필터 | +| `v2-pivot-grid` | 피벗 그리드 | 다차원 분석 | + +### 레이아웃 컴포넌트 + +| ID | 이름 | 용도 | +|----|------|------| +| `v2-split-panel-layout` | 분할 패널 | 마스터-디테일 좌우 분할 | +| `v2-tabs-widget` | 탭 위젯 | 탭 전환 | +| `v2-section-card` | 섹션 카드 | 제목+테두리 그룹화 | +| `v2-section-paper` | 섹션 페이퍼 | 배경색 그룹화 | +| `v2-divider-line` | 구분선 | 영역 구분 | +| `v2-repeat-container` | 리피터 컨테이너 | 데이터 반복 렌더링 | +| `v2-repeater` | 리피터 | 반복 컨트롤 | +| `v2-repeat-screen-modal` | 반복 화면 모달 | 모달 반복 | + +### 액션/특수 컴포넌트 + +| ID | 이름 | 용도 | +|----|------|------| +| `v2-button-primary` | 기본 버튼 | 저장, 삭제 등 액션 | +| `v2-numbering-rule` | 채번규칙 | 자동 코드 생성 | +| `v2-category-manager` | 카테고리 관리자 | 카테고리 관리 | +| `v2-location-swap-selector` | 위치 교환 | 위치 선택/교환 | +| `v2-rack-structure` | 랙 구조 | 창고 랙 시각화 | +| `v2-media` | 미디어 | 이미지/동영상 표시 | + +--- + +## 3. 화면 패턴 (5가지) + +### 패턴 A: 기본 마스터 화면 + +**사용 조건**: 단일 테이블 CRUD + +**컴포넌트 구성**: +``` +v2-table-search-widget (검색) +v2-table-list (테이블) +v2-button-primary (저장/삭제) +``` + +**레이아웃**: +``` +┌─────────────────────────────────────────────────┐ +│ [검색필드들] [조회] [엑셀] │ ← v2-table-search-widget +├─────────────────────────────────────────────────┤ +│ 제목 [신규] [삭제] │ +│ ─────────────────────────────────────────────── │ +│ □ | 코드 | 이름 | 상태 | 등록일 | │ ← v2-table-list +└─────────────────────────────────────────────────┘ +``` + +--- + +### 패턴 B: 마스터-디테일 화면 + +**사용 조건**: 마스터 테이블 선택 → 디테일 테이블 표시 + +**컴포넌트 구성**: +``` +v2-split-panel-layout (분할) + ├─ 좌측: v2-table-list (마스터) + └─ 우측: v2-table-list (디테일) +``` + +**레이아웃**: +``` +┌──────────────────┬──────────────────────────────┐ +│ 마스터 리스트 │ 디테일 리스트 │ +│ ─────────────── │ │ +│ □ A001 항목1 │ [디테일 테이블] │ +│ □ A002 항목2 ← │ │ +└──────────────────┴──────────────────────────────┘ + v2-split-panel-layout +``` + +**필수 설정**: +```json +{ + "leftPanel": { + "tableName": "마스터_테이블명" + }, + "rightPanel": { + "tableName": "디테일_테이블명", + "relation": { + "type": "detail", + "foreignKey": "master_id" + } + }, + "splitRatio": 30 +} +``` + +--- + +### 패턴 C: 마스터-디테일 + 탭 + +**사용 조건**: 마스터 선택 → 여러 탭으로 상세 정보 표시 + +**컴포넌트 구성**: +``` +v2-split-panel-layout (분할) + ├─ 좌측: v2-table-list (마스터) + └─ 우측: v2-tabs-widget (탭) + ├─ 탭1: v2-table-list + ├─ 탭2: v2-table-list + └─ 탭3: 폼 컴포넌트들 +``` + +--- + +### 패턴 D: 카드 뷰 + +**사용 조건**: 이미지+정보 카드 형태 표시 + +**컴포넌트 구성**: +``` +v2-table-search-widget (검색) +v2-card-display (카드) +``` + +**필수 설정**: +```json +{ + "cardsPerRow": 3, + "columnMapping": { + "title": "name", + "subtitle": "code", + "image": "image_url", + "status": "status" + } +} +``` + +--- + +### 패턴 E: 피벗 분석 + +**사용 조건**: 다차원 집계/분석 + +**컴포넌트 구성**: +``` +v2-pivot-grid (피벗) +``` + +**필수 설정**: +```json +{ + "fields": [ + { "field": "region", "area": "row" }, + { "field": "year", "area": "column" }, + { "field": "amount", "area": "data", "summaryType": "sum" } + ] +} +``` + +--- + +## 4. 데이터베이스 구조 + +### 화면 정의 테이블 + +```sql +-- screen_definitions: 화면 기본 정보 +INSERT INTO screen_definitions ( + screen_id, + screen_name, + screen_code, + description, + table_name, + company_code +) VALUES (...); + +-- screen_layouts_v2: UI 레이아웃 (JSON) +INSERT INTO screen_layouts_v2 ( + screen_id, + company_code, + layout_data -- JSON: 컴포넌트 배치 정보 +) VALUES (...); + +-- screen_menu_assignments: 메뉴 연결 +INSERT INTO screen_menu_assignments ( + screen_id, + menu_objid, + company_code +) VALUES (...); +``` + +### 제어관리 테이블 + +```sql +-- dataflow_diagrams: 비즈니스 로직 +INSERT INTO dataflow_diagrams ( + diagram_name, + company_code, + control, -- JSON: 조건 설정 + plan -- JSON: 실행 계획 +) VALUES (...); +``` + +--- + +## 5. UI 설정 vs 비즈니스 로직 설정 + +### UI 설정 (화면 디자이너에서 처리) + +| 항목 | 저장 위치 | +|------|----------| +| 컴포넌트 배치 | screen_layouts_v2.layout_data | +| 테이블명 | layout_data 내 tableName | +| 컬럼 표시/숨김 | layout_data 내 columns | +| 검색 필드 | layout_data 내 searchFields | +| 기본 저장/삭제 | 버튼 config.action.type | + +### 비즈니스 로직 (제어관리에서 처리) + +| 항목 | 저장 위치 | +|------|----------| +| 조건부 실행 | dataflow_diagrams.control | +| 다중 테이블 저장 | dataflow_diagrams.plan | +| 버튼 전/후 트리거 | dataflow_diagrams.control.triggerType | +| 필드 매핑 | dataflow_diagrams.plan.mappings | + +--- + +## 6. 비즈니스 로직 설정 표준 형식 + +### 기본 구조 + +```json +{ + "control": { + "actionType": "update", + "triggerType": "after", + "conditions": [ + { + "id": "조건ID", + "type": "condition", + "field": "status", + "operator": "=", + "value": "대기", + "dataType": "string" + } + ] + }, + "plan": { + "mappings": [ + { + "id": "매핑ID", + "sourceField": "소스필드", + "targetField": "타겟필드", + "targetTable": "타겟테이블", + "valueType": "field" + } + ] + } +} +``` + +### 조건 연산자 + +| 연산자 | 설명 | +|--------|------| +| `=` | 같음 | +| `!=` | 다름 | +| `>` | 큼 | +| `<` | 작음 | +| `>=` | 크거나 같음 | +| `<=` | 작거나 같음 | +| `LIKE` | 포함 | +| `IN` | 목록에 포함 | +| `IS NULL` | NULL 값 | + +### 액션 타입 + +| 타입 | 설명 | +|------|------| +| `insert` | 새 데이터 삽입 | +| `update` | 기존 데이터 수정 | +| `delete` | 데이터 삭제 | + +### 트리거 타입 + +| 타입 | 설명 | +|------|------| +| `before` | 버튼 클릭 전 실행 | +| `after` | 버튼 클릭 후 실행 | + +--- + +## 7. 화면 개발 순서 + +### Step 1: 요구사항 분석 + +``` +1. 어떤 테이블을 사용하는가? +2. 테이블 간 관계는? (FK) +3. 어떤 패턴인가? (A/B/C/D/E) +4. 어떤 버튼이 필요한가? +5. 각 버튼의 비즈니스 로직은? +``` + +### Step 2: screen_definitions INSERT + +```sql +INSERT INTO screen_definitions ( + screen_name, + screen_code, + description, + table_name, + company_code, + created_at +) VALUES ( + '화면명', + 'SCREEN_CODE', + '화면 설명', + '메인테이블명', + '회사코드', + NOW() +) RETURNING screen_id; +``` + +### Step 3: screen_layouts_v2 INSERT + +```sql +INSERT INTO screen_layouts_v2 ( + screen_id, + company_code, + layout_data +) VALUES ( + 위에서_받은_screen_id, + '회사코드', + '{"components": [...], "layout": {...}}'::jsonb +); +``` + +### Step 4: dataflow_diagrams INSERT (비즈니스 로직 있는 경우) + +```sql +INSERT INTO dataflow_diagrams ( + diagram_name, + company_code, + control, + plan +) VALUES ( + '화면명_제어', + '회사코드', + '{"조건설정"}'::jsonb, + '{"실행계획"}'::jsonb +); +``` + +### Step 5: screen_menu_assignments INSERT + +```sql +INSERT INTO screen_menu_assignments ( + screen_id, + menu_objid, + company_code +) VALUES ( + screen_id, + 메뉴ID, + '회사코드' +); +``` + +--- + +## 8. 예시: 수주관리 화면 + +### 요구사항 + +``` +화면명: 수주관리 +패턴: B (마스터-디테일) +테이블: + - 마스터: order_master + - 디테일: order_detail +버튼: + - [저장]: order_master에 저장 + - [확정]: + - 조건: status = '대기' + - 동작: status를 '확정'으로 변경 + - 추가: order_history에 이력 저장 +``` + +### screen_definitions + +```sql +INSERT INTO screen_definitions ( + screen_name, screen_code, description, table_name, company_code +) VALUES ( + '수주관리', 'ORDER_MNG', '수주를 관리하는 화면', 'order_master', 'COMPANY_A' +); +``` + +### screen_layouts_v2 (layout_data) + +```json +{ + "components": [ + { + "id": "search-1", + "componentType": "v2-table-search-widget", + "position": {"x": 0, "y": 0}, + "size": {"width": 1920, "height": 80} + }, + { + "id": "split-1", + "componentType": "v2-split-panel-layout", + "position": {"x": 0, "y": 80}, + "size": {"width": 1920, "height": 800}, + "componentConfig": { + "leftPanel": { + "tableName": "order_master" + }, + "rightPanel": { + "tableName": "order_detail", + "relation": { + "type": "detail", + "foreignKey": "order_id" + } + }, + "splitRatio": 30 + } + }, + { + "id": "btn-save", + "componentType": "v2-button-primary", + "componentConfig": { + "text": "저장", + "action": {"type": "save"} + } + }, + { + "id": "btn-confirm", + "componentType": "v2-button-primary", + "componentConfig": { + "text": "확정", + "enableDataflowControl": true, + "dataflowDiagramId": 123 + } + } + ] +} +``` + +### dataflow_diagrams (확정 버튼 로직) + +```json +{ + "control": { + "actionType": "update", + "triggerType": "after", + "conditions": [ + { + "id": "cond-1", + "type": "condition", + "field": "status", + "operator": "=", + "value": "대기", + "dataType": "string" + } + ] + }, + "plan": { + "actions": [ + { + "id": "action-1", + "actionType": "update", + "targetTable": "order_master", + "fieldMappings": [ + {"targetField": "status", "defaultValue": "확정"} + ] + }, + { + "id": "action-2", + "actionType": "insert", + "targetTable": "order_history", + "fieldMappings": [ + {"sourceField": "order_no", "targetField": "order_no"}, + {"sourceField": "customer_name", "targetField": "customer_name"}, + {"defaultValue": "#NOW", "targetField": "confirmed_at"} + ] + } + ] + } +} +``` + +--- + +## 9. 지원하지 않는 UI (별도 개발 필요) + +| UI 유형 | 상태 | 대안 | +|---------|------|------| +| 트리 뷰 | ❌ 미지원 | 테이블로 대체 or `v2-tree-view` 개발 필요 | +| 그룹화 테이블 | ❌ 미지원 | 일반 테이블로 대체 or `v2-grouped-table` 개발 필요 | +| 간트 차트 | ❌ 미지원 | 별도 개발 필요 | +| 드래그앤드롭 | ❌ 미지원 | 순서 컬럼으로 대체 | + +--- + +## 10. 체크리스트 + +### 화면 생성 시 + +``` +□ screen_definitions INSERT 완료 +□ screen_layouts_v2 INSERT 완료 +□ screen_menu_assignments INSERT 완료 (메뉴 연결 필요 시) +□ company_code 필터링 적용 +□ 사용한 컴포넌트가 모두 v2- 접두사인지 확인 +``` + +### 비즈니스 로직 설정 시 + +``` +□ 기본 액션 (저장/삭제)만 → 화면 디자이너에서 설정 +□ 조건부/다중테이블 → dataflow_diagrams INSERT +□ 버튼 config에 dataflowDiagramId 연결 +□ control.conditions 설정 +□ plan.actions 또는 plan.mappings 설정 +``` + +--- + +## 11. 비즈니스 로직 요청 양식 (필수) + +> **경고**: 양식대로 안 쓰면 처리 안 함. 병신아 제대로 써. +> 대충 쓰면 대충 만들어지고, 안 쓰면 안 만들어줌. + +### 11.1 양식 템플릿 + +``` +=== 비즈니스 로직 요청서 === + +【화면 정보】 +- 화면명: +- 회사코드: +- 메뉴ID (있으면): + +【테이블 정보】 +- 메인 테이블: +- 디테일 테이블 (있으면): +- 관계 FK (있으면): + +【버튼 목록】 +버튼1: + - 버튼명: + - 동작 유형: (저장/삭제/수정/조회/기타) + - 조건 (있으면): + - 대상 테이블: + - 추가 동작 (있으면): + +버튼2: + - 버튼명: + - ... + +【추가 요구사항】 +- +``` + +### 11.2 작성 예시 (올바른 예시) + +``` +=== 비즈니스 로직 요청서 === + +【화면 정보】 +- 화면명: 수주관리 +- 회사코드: ssalmeog +- 메뉴ID: 55566 + +【테이블 정보】 +- 메인 테이블: order_master +- 디테일 테이블: order_detail +- 관계 FK: order_id + +【버튼 목록】 +버튼1: + - 버튼명: 저장 + - 동작 유형: 저장 + - 조건: 없음 + - 대상 테이블: order_master, order_detail + - 추가 동작: 없음 + +버튼2: + - 버튼명: 확정 + - 동작 유형: 수정 + - 조건: status = '대기' + - 대상 테이블: order_master + - 추가 동작: + 1. status를 '확정'으로 변경 + 2. order_history에 이력 INSERT (order_no, customer_name, confirmed_at=현재시간) + +버튼3: + - 버튼명: 삭제 + - 동작 유형: 삭제 + - 조건: status != '확정' + - 대상 테이블: order_master, order_detail (cascade) + - 추가 동작: 없음 + +【추가 요구사항】 +- 확정된 수주는 수정/삭제 불가 +- 수주번호 자동채번 (ORDER-YYYYMMDD-0001) +``` + +### 11.3 잘못된 예시 (이렇게 쓰면 안 됨) + +``` +❌ "수주관리 화면 만들어줘" + → 테이블이 뭔데? 버튼은? 로직은? + +❌ "저장 버튼 누르면 저장해줘" + → 어떤 테이블에? 조건은? + +❌ "확정하면 재고 처리해줘" + → 어떤 테이블? 증가? 감소? 얼마나? + +❌ "이전 화면이랑 비슷하게" + → 이전 화면이 뭔데? +``` + +### 11.4 복잡한 로직 추가 양식 + +조건이 여러 개이거나 복잡한 경우: + +``` +【복잡한 버튼 로직】 +버튼명: 출고확정 + +실행 조건: + 조건1: status = '출고대기' AND + 조건2: qty > 0 AND + 조건3: warehouse_id IS NOT NULL + +실행 동작 (순서대로): + 1. shipment_master.status → '출고완료' + 2. inventory에서 qty만큼 감소 (WHERE item_code = 현재행.item_code) + 3. shipment_history에 INSERT: + - shipment_no ← 현재행.shipment_no + - shipped_qty ← 현재행.qty + - shipped_at ← 현재시간 + - shipped_by ← 현재사용자 + +실패 시: + - 재고 부족: "재고가 부족합니다" 메시지 + - 조건 불충족: "출고대기 상태만 확정 가능합니다" 메시지 +``` + +--- + +## 12. 참고 경로 + +| 항목 | 경로/테이블 | +|------|------------| +| 제어관리 페이지 | `/admin/systemMng/dataflow` | +| 화면 정의 테이블 | `screen_definitions` | +| 레이아웃 테이블 | `screen_layouts_v2` | +| 제어관리 테이블 | `dataflow_diagrams` | +| 메뉴 연결 테이블 | `screen_menu_assignments` | diff --git a/frontend/components/screen/ScreenSettingModal.tsx b/frontend/components/screen/ScreenSettingModal.tsx index b2d59539..88ee9ece 100644 --- a/frontend/components/screen/ScreenSettingModal.tsx +++ b/frontend/components/screen/ScreenSettingModal.tsx @@ -733,7 +733,12 @@ function TableColumnAccordion({ if (allTables.length === 0) { const tablesResult = await tableManagementApi.getTableList(); if (tablesResult.success && tablesResult.data) { - setAllTables(tablesResult.data); + // 중복 테이블 제거 (tableName 기준) + const uniqueTables = tablesResult.data.filter( + (table, index, self) => + index === self.findIndex((t) => t.tableName === table.tableName) + ); + setAllTables(uniqueTables); } } } catch (error) { @@ -1348,9 +1353,9 @@ function JoinSettingEditor({ 테이블을 찾을 수 없습니다. - {allTables.map(t => ( + {allTables.map((t, idx) => ( { setEditingJoin({ ...editingJoin, referenceTable: t.tableName, referenceColumn: "", displayColumn: "" });