Merge branch 'feature/v2-unified-renewal' of http://39.117.244.52:3000/kjs/ERP-node into feature/v2-renewal

; Please enter a commit message to explain why this merge is necessary,
; especially if it merges an updated upstream into a topic branch.
;
; Lines starting with ';' will be ignored, and an empty message aborts
; the commit.
This commit is contained in:
DDD1542 2026-01-30 14:22:24 +09:00
commit 4daa77f9a1
26 changed files with 6765 additions and 14 deletions

View File

@ -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)
---
## 🚨 최우선 보안 규칙: 멀티테넌시
**모든 코드 작성/수정 완료 후 반드시 다음 파일을 확인하세요:**

View File

@ -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
}
]
}

View File

@ -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
}
]
}

View File

@ -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
}
]
}

View File

@ -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
}
]
}

View File

@ -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 (타임라인, 모바일 스타일)로 개별 개발 필요

View File

@ -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 구조만
**별도 설정 필요한 것**: 저장 테이블, 버튼 액션, 조건 처리, 다중 행 처리

View File

@ -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개 화면)

View File

@ -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개 이상 화면에서 사용 가능
- 거래처관리, 품목정보, 작업지시, 입출고관리, 견적관리

File diff suppressed because it is too large Load Diff

View File

@ -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% 구현 가능**

View File

@ -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) (예정)

View File

@ -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 개발 시 재활용 가능**

View File

@ -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 컴포넌트로 핵심 기능 구현 가능**

View File

@ -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 컴포넌트로 완전 구현 가능**

View File

@ -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 개발 시 그룹화 기능 추가 가능**

View File

@ -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 컴포넌트로 핵심 기능 구현 가능**

View File

@ -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
# 범례: ✅ 완전구현 | ⚠️ 부분구현 | ❌ 신규개발필요
```
## 문서 작성 형식

View File

@ -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` |

View File

@ -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` |

View File

@ -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({
<CommandList>
<CommandEmpty className="text-xs py-2"> .</CommandEmpty>
<CommandGroup>
{allTables.map(t => (
{allTables.map((t, idx) => (
<CommandItem
key={t.tableName}
key={`${t.tableName}-${idx}`}
value={t.displayName || t.tableName}
onSelect={() => {
setEditingJoin({ ...editingJoin, referenceTable: t.tableName, referenceColumn: "", displayColumn: "" });