카드 디스플레이 옵션 설정

This commit is contained in:
kjs
2025-12-23 13:53:22 +09:00
parent 01e47a1830
commit 9c26738604
8 changed files with 963 additions and 1065 deletions
@@ -42,7 +42,14 @@ export interface ComponentRenderer {
// 테이블 선택된 행 정보 (다중 선택 액션용)
selectedRows?: any[];
selectedRowsData?: any[];
onSelectedRowsChange?: (selectedRows: any[], selectedRowsData: any[], sortBy?: string, sortOrder?: "asc" | "desc", columnOrder?: string[], tableDisplayData?: any[]) => void;
onSelectedRowsChange?: (
selectedRows: any[],
selectedRowsData: any[],
sortBy?: string,
sortOrder?: "asc" | "desc",
columnOrder?: string[],
tableDisplayData?: any[],
) => void;
// 테이블 정렬 정보 (엑셀 다운로드용)
sortBy?: string;
sortOrder?: "asc" | "desc";
@@ -126,7 +133,14 @@ export interface DynamicComponentRendererProps {
// 🆕 비활성화할 필드 목록 (EditModal → 각 컴포넌트)
disabledFields?: string[];
selectedRowsData?: any[];
onSelectedRowsChange?: (selectedRows: any[], selectedRowsData: any[], sortBy?: string, sortOrder?: "asc" | "desc", columnOrder?: string[], tableDisplayData?: any[]) => void;
onSelectedRowsChange?: (
selectedRows: any[],
selectedRowsData: any[],
sortBy?: string,
sortOrder?: "asc" | "desc",
columnOrder?: string[],
tableDisplayData?: any[],
) => void;
// 테이블 정렬 정보 (엑셀 다운로드용)
sortBy?: string;
sortOrder?: "asc" | "desc";
@@ -146,7 +160,7 @@ export interface DynamicComponentRendererProps {
// 모달 내에서 렌더링 여부
isInModal?: boolean;
// 탭 관련 정보 (탭 내부의 컴포넌트에서 사용)
parentTabId?: string; // 부모 탭 ID
parentTabId?: string; // 부모 탭 ID
parentTabsComponentId?: string; // 부모 탭 컴포넌트 ID
// 🆕 조건부 비활성화 상태
conditionalDisabled?: boolean;
@@ -172,7 +186,7 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
const config = (component as any).componentConfig || {};
const fieldName = (component as any).columnName || component.id;
const currentValue = props.formData?.[fieldName];
const handleChange = (value: any) => {
if (props.onFormDataChange) {
props.onFormDataChange(fieldName, value);
@@ -259,6 +273,9 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
);
case "unified-list":
// 데이터 소스: config.data > props.tableDisplayData > []
const listData = config.data?.length > 0 ? config.data : props.tableDisplayData || [];
return (
<UnifiedList
unifiedType="UnifiedList"
@@ -271,8 +288,28 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
pagination: config.pagination,
searchable: config.searchable,
editable: config.editable,
pageable: config.pageable,
pageSize: config.pageSize,
cardConfig: config.cardConfig,
dataSource: {
table: config.dataSource?.table || props.tableName,
},
}}
data={config.data || []}
data={listData}
selectedRows={props.selectedRowsData || []}
onRowSelect={
props.onSelectedRowsChange
? (rows) =>
props.onSelectedRowsChange?.(
rows.map((r: any) => r.id || r.objid),
rows,
props.sortBy,
props.sortOrder,
undefined,
props.tableDisplayData,
)
: undefined
}
/>
);
@@ -372,17 +409,22 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
const webType = (component as any).componentConfig?.webType;
const tableName = (component as any).tableName;
const columnName = (component as any).columnName;
// 카테고리 셀렉트: webType이 "category"이고 tableName과 columnName이 있는 경우만
// ⚠️ 단, componentType이 "select-basic"인 경우는 ComponentRegistry로 처리 (다중선택 등 고급 기능 지원)
if ((inputType === "category" || webType === "category") && tableName && columnName && componentType === "select-basic") {
if (
(inputType === "category" || webType === "category") &&
tableName &&
columnName &&
componentType === "select-basic"
) {
// select-basic은 ComponentRegistry에서 처리하도록 아래로 통과
} else if ((inputType === "category" || webType === "category") && tableName && columnName) {
try {
const { CategorySelectComponent } = require("@/lib/registry/components/category-select/CategorySelectComponent");
const fieldName = columnName || component.id;
const currentValue = props.formData?.[fieldName] || "";
const handleChange = (value: any) => {
if (props.onFormDataChange) {
props.onFormDataChange(fieldName, value);
@@ -496,7 +538,7 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
// 컴포넌트의 columnName에 해당하는 formData 값 추출
const fieldName = (component as any).columnName || component.id;
// modal-repeater-table은 배열 데이터를 다루므로 빈 배열로 초기화
let currentValue;
if (componentType === "modal-repeater-table" || componentType === "repeat-screen-modal") {
@@ -505,7 +547,7 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
} else {
currentValue = formData?.[fieldName] || "";
}
// onChange 핸들러 - 컴포넌트 타입에 따라 다르게 처리
const handleChange = (value: any) => {
// autocomplete-search-input, entity-search-input은 자체적으로 onFormDataChange를 호출하므로 중복 저장 방지
@@ -551,10 +593,11 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
};
// 🆕 엔티티 검색 컴포넌트는 componentConfig.tableName을 사용해야 함 (화면 테이블이 아닌 검색 대상 테이블)
const useConfigTableName = componentType === "entity-search-input" ||
componentType === "autocomplete-search-input" ||
componentType === "modal-repeater-table";
const useConfigTableName =
componentType === "entity-search-input" ||
componentType === "autocomplete-search-input" ||
componentType === "modal-repeater-table";
const rendererProps = {
component,
isSelected,
@@ -578,7 +621,7 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
onFormDataChange,
onChange: handleChange, // 개선된 onChange 핸들러 전달
// 🆕 엔티티 검색 컴포넌트는 componentConfig.tableName 유지, 그 외는 화면 테이블명 사용
tableName: useConfigTableName ? (component.componentConfig?.tableName || tableName) : tableName,
tableName: useConfigTableName ? component.componentConfig?.tableName || tableName : tableName,
menuId, // 🆕 메뉴 ID
menuObjid, // 🆕 메뉴 OBJID (메뉴 스코프)
selectedScreen, // 🆕 화면 정보
@@ -677,10 +720,10 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
// 폴백 렌더링 - 기본 플레이스홀더
return (
<div className="flex h-full w-full items-center justify-center rounded border-2 border-dashed border-border bg-muted p-4">
<div className="border-border bg-muted flex h-full w-full items-center justify-center rounded border-2 border-dashed p-4">
<div className="text-center">
<div className="mb-2 text-sm font-medium text-muted-foreground">{component.label || component.id}</div>
<div className="text-xs text-muted-foreground/70"> : {componentType}</div>
<div className="text-muted-foreground mb-2 text-sm font-medium">{component.label || component.id}</div>
<div className="text-muted-foreground/70 text-xs"> : {componentType}</div>
</div>
</div>
);