From eef1451c5a585885780d80dfc001a9d3c18a008a Mon Sep 17 00:00:00 2001 From: kjs Date: Tue, 18 Nov 2025 10:21:36 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=ED=95=AD=EB=AA=A9=20=ED=91=9C=EC=8B=9C?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95=EC=9D=84=20=EA=B7=B8=EB=A3=B9=EB=B3=84?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FieldGroup에 displayItems 추가 (그룹별 독립적인 표시 설정) - SelectedItemsDetailInputConfig에서 전역 displayItems 제거 - renderDisplayItems에 groupId 파라미터 추가하여 그룹별 설정 사용 - 설정 패널에서 그룹별로 displayItems 관리 - 각 그룹마다 다른 표시 형식 가능 (예: 거래처 정보 vs 단가 정보) - 그룹의 필드만 선택 가능하도록 필터링 --- .../SelectedItemsDetailInputComponent.tsx | 20 +- .../SelectedItemsDetailInputConfigPanel.tsx | 477 ++++++++---------- .../selected-items-detail-input/types.ts | 8 +- 3 files changed, 228 insertions(+), 277 deletions(-) diff --git a/frontend/lib/registry/components/selected-items-detail-input/SelectedItemsDetailInputComponent.tsx b/frontend/lib/registry/components/selected-items-detail-input/SelectedItemsDetailInputComponent.tsx index da16a349..4bdb1a2e 100644 --- a/frontend/lib/registry/components/selected-items-detail-input/SelectedItemsDetailInputComponent.tsx +++ b/frontend/lib/registry/components/selected-items-detail-input/SelectedItemsDetailInputComponent.tsx @@ -544,13 +544,19 @@ export const SelectedItemsDetailInputComponent: React.FC { - const displayItems = componentConfig.displayItems || []; + // 🆕 displayItems를 렌더링하는 헬퍼 함수 (그룹별) + const renderDisplayItems = useCallback((entry: GroupEntry, item: ItemData, groupId: string) => { + // 🆕 해당 그룹의 displayItems 가져오기 + const group = (componentConfig.fieldGroups || []).find(g => g.id === groupId); + const displayItems = group?.displayItems || []; if (displayItems.length === 0) { - // displayItems가 없으면 기본 방식 (모든 필드 나열) - const fields = componentConfig.additionalFields || []; + // displayItems가 없으면 기본 방식 (해당 그룹의 필드만 나열) + const fields = (componentConfig.additionalFields || []).filter(f => + componentConfig.fieldGroups && componentConfig.fieldGroups.length > 0 + ? f.groupId === groupId + : true + ); return fields.map((f) => entry[f.name] || "-").join(" / "); } @@ -694,7 +700,7 @@ export const SelectedItemsDetailInputComponent: React.FC ); - }, [componentConfig.displayItems, componentConfig.additionalFields]); + }, [componentConfig.fieldGroups, componentConfig.additionalFields]); // 빈 상태 렌더링 if (items.length === 0) { @@ -805,7 +811,7 @@ export const SelectedItemsDetailInputComponent: React.FC handleEditGroupEntry(item.id, group.id, entry.id)} > - {idx + 1}. {renderDisplayItems(entry, item)} + {idx + 1}. {renderDisplayItems(entry, item, group.id)} + + + + + +

+ 이 그룹의 입력 항목이 추가되면 어떻게 표시될지 설정 +

+ + {(!group.displayItems || group.displayItems.length === 0) ? ( +
+ 미설정 (모든 필드를 " / "로 구분하여 표시) +
+ ) : ( +
+ {group.displayItems.map((item, itemIndex) => ( +
+ {/* 헤더 */} +
+ + {item.type === "icon" && "🎨"} + {item.type === "field" && "📝"} + {item.type === "text" && "💬"} + {item.type === "badge" && "🏷️"} + + +
+ + {/* 아이콘 설정 */} + {item.type === "icon" && ( + updateDisplayItemInGroup(group.id, itemIndex, { icon: e.target.value })} + placeholder="Building" + className="h-6 text-[9px] sm:text-[10px]" + /> + )} + + {/* 텍스트 설정 */} + {item.type === "text" && ( + updateDisplayItemInGroup(group.id, itemIndex, { value: e.target.value })} + placeholder="| , / , -" + className="h-6 text-[9px] sm:text-[10px]" + /> + )} + + {/* 필드 설정 */} + {item.type === "field" && ( +
+ {/* 필드 선택 */} + + + {/* 라벨 */} + updateDisplayItemInGroup(group.id, itemIndex, { label: e.target.value })} + placeholder="거래처:" + className="h-6 text-[9px] sm:text-[10px]" + /> + + {/* 표시 형식 */} + + + {/* 빈 값 처리 */} +
+ + + {/* 기본값 */} + {item.emptyBehavior === "default" && ( + updateDisplayItemInGroup(group.id, itemIndex, { defaultValue: e.target.value })} + placeholder="미입력" + className="h-6 text-[9px] sm:text-[10px]" + /> + )} +
+
+ )} +
+ ))} +
+ )} + ))} @@ -761,252 +956,6 @@ export const SelectedItemsDetailInputConfigPanel: React.FC - {/* 🆕 항목 표시 설정 */} -
-
- -
- - - -
-
- -

- 각 입력 항목이 추가되면 어떻게 표시될지 설정합니다 -

- - {displayItems.length === 0 ? ( -
- 표시 항목이 없습니다. 위의 버튼으로 추가하세요. -
- (미설정 시 모든 필드를 " / "로 구분하여 표시) -
- ) : ( -
- {displayItems.map((item, index) => ( - - - {/* 헤더 */} -
- - {item.type === "icon" && "🎨 아이콘"} - {item.type === "field" && "📝 필드"} - {item.type === "text" && "💬 텍스트"} - {item.type === "badge" && "🏷️ 배지"} - - -
- - {/* 아이콘 설정 */} - {item.type === "icon" && ( -
-
- - updateDisplayItem(index, { icon: e.target.value })} - placeholder="예: Building, User, Package" - className="h-7 text-xs" - /> -

- lucide-react 아이콘 이름을 입력하세요 -

-
-
- )} - - {/* 텍스트 설정 */} - {item.type === "text" && ( -
- - updateDisplayItem(index, { value: e.target.value })} - placeholder="예: | , / , - " - className="h-7 text-xs" - /> -
- )} - - {/* 필드 설정 */} - {item.type === "field" && ( -
- {/* 필드 선택 */} -
- - -
- - {/* 라벨 */} -
- - updateDisplayItem(index, { label: e.target.value })} - placeholder="예: 거래처:, 단가:" - className="h-7 text-xs" - /> -
- - {/* 표시 형식 */} -
- - -
- - {/* 빈 값 처리 */} -
- - -
- - {/* 기본값 (emptyBehavior가 "default"일 때만) */} - {item.emptyBehavior === "default" && ( -
- - updateDisplayItem(index, { defaultValue: e.target.value })} - placeholder="예: 미입력, 0, -" - className="h-7 text-xs" - /> -
- )} -
- )} - - {/* 스타일 설정 */} -
- -
- - - -
- - {/* 색상 */} -
-
- - updateDisplayItem(index, { color: e.target.value })} - className="h-7 w-full" - /> -
-
- - updateDisplayItem(index, { backgroundColor: e.target.value })} - className="h-7 w-full" - /> -
-
-
-
-
- ))} -
- )} -
- {/* 사용 예시 */}

💡 사용 예시

diff --git a/frontend/lib/registry/components/selected-items-detail-input/types.ts b/frontend/lib/registry/components/selected-items-detail-input/types.ts index 6685fc50..05c11e4a 100644 --- a/frontend/lib/registry/components/selected-items-detail-input/types.ts +++ b/frontend/lib/registry/components/selected-items-detail-input/types.ts @@ -50,6 +50,8 @@ export interface FieldGroup { description?: string; /** 그룹 표시 순서 */ order?: number; + /** 🆕 이 그룹의 항목 표시 설정 (그룹별로 다른 표시 형식 가능) */ + displayItems?: DisplayItem[]; } /** @@ -115,12 +117,6 @@ export interface SelectedItemsDetailInputConfig extends ComponentConfig { */ inputMode?: "inline" | "modal"; - /** - * 🆕 항목 표시 설정 (각 그룹의 입력 항목을 어떻게 표시할지) - * 예: [{ type: "icon", icon: "Building" }, { type: "field", fieldName: "customer_name", label: "거래처:" }] - */ - displayItems?: DisplayItem[]; - /** * 빈 상태 메시지 */