feat: V2Input 및 DynamicComponentRenderer에서 tableName 및 inputType 처리 개선

- V2Input 컴포넌트에서 tableName을 여러 소스(프롭스, 설정, 오버라이드, 화면 정보)에서 추출하도록 로직을 개선하였습니다.
- inputType을 props에서 직접 전달받거나 config에서 설정된 값으로 확인하도록 수정하여 유연성을 높였습니다.
- DynamicComponentRenderer에서 v2-input 컴포넌트의 tableName을 올바르게 처리하도록 업데이트하였습니다.
- 채번 규칙 ID를 formData에 저장하는 로직을 개선하여 데이터 처리의 일관성을 강화하였습니다.
This commit is contained in:
kjs 2026-02-04 10:21:57 +09:00
parent dff27c522f
commit f7dda7a666
3 changed files with 52 additions and 15 deletions

View File

@ -361,8 +361,17 @@ export const V2Input = forwardRef<HTMLDivElement, V2InputProps>((props, ref) =>
const [isGeneratingNumbering, setIsGeneratingNumbering] = useState(false);
const hasGeneratedNumberingRef = useRef(false);
// tableName 추출 (props에서 전달받거나 config에서)
const tableName = (props as any).tableName || (config as any).tableName;
// tableName 추출 (여러 소스에서 확인)
// 1. props에서 직접 전달받은 값
// 2. config에서 설정된 값
// 3. 컴포넌트 overrides에서 설정된 값 (V2 레이아웃)
// 4. screenInfo에서 화면 테이블명
const tableName =
(props as any).tableName ||
(config as any).tableName ||
(props as any).component?.tableName ||
(props as any).component?.overrides?.tableName ||
(props as any).screenInfo?.tableName;
// 수정 모드 여부 확인
const originalData = (props as any).originalData || (props as any)._originalData;
@ -445,8 +454,10 @@ export const V2Input = forwardRef<HTMLDivElement, V2InputProps>((props, ref) =>
// formData에서 카테고리 관련 값 추출 (채번 파트에서 카테고리 사용 시)
// 채번 필드 자체의 값은 제외해야 함 (무한 루프 방지)
// inputType을 여러 소스에서 확인
const propsInputType = (props as any).inputType;
const categoryValuesForNumbering = useMemo(() => {
const inputType = config.inputType || config.type || "text";
const inputType = propsInputType || config.inputType || config.type || "text";
if (inputType !== "numbering") return "";
// formData에서 category 타입 필드 값들을 추출 (채번 필드 자체는 제외)
const categoryFields: Record<string, string> = {};
@ -458,12 +469,13 @@ export const V2Input = forwardRef<HTMLDivElement, V2InputProps>((props, ref) =>
}
}
return JSON.stringify(categoryFields);
}, [config.inputType, config.type, formData, columnName]);
}, [propsInputType, config.inputType, config.type, formData, columnName]);
// 채번 타입 자동생성 로직 (테이블 관리에서 설정된 numberingRuleId 사용)
useEffect(() => {
const generateNumberingCode = async () => {
const inputType = config.inputType || config.type || "text";
// inputType을 여러 소스에서 확인 (props에서 직접 전달받거나 config에서)
const inputType = (props as any).inputType || config.inputType || config.type || "text";
// numbering 타입이 아니면 스킵
if (inputType !== "numbering") {
@ -524,9 +536,12 @@ export const V2Input = forwardRef<HTMLDivElement, V2InputProps>((props, ref) =>
}
// detailSettings에서 numberingRuleId 추출
if (targetColumn.detailSettings && typeof targetColumn.detailSettings === "string") {
if (targetColumn.detailSettings) {
try {
const parsed = JSON.parse(targetColumn.detailSettings);
// 문자열이면 파싱, 객체면 그대로 사용
const parsed = typeof targetColumn.detailSettings === "string"
? JSON.parse(targetColumn.detailSettings)
: targetColumn.detailSettings;
numberingRuleIdRef.current = parsed.numberingRuleId || null;
// 🆕 채번 규칙 ID를 formData에 저장 (저장 시 allocateCode 호출을 위해)
@ -618,7 +633,7 @@ export const V2Input = forwardRef<HTMLDivElement, V2InputProps>((props, ref) =>
// 타입별 입력 컴포넌트 렌더링
const renderInput = () => {
const inputType = config.inputType || config.type || "text";
const inputType = propsInputType || config.inputType || config.type || "text";
switch (inputType) {
case "text":
return (

View File

@ -506,10 +506,12 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
};
// 🆕 엔티티 검색 컴포넌트는 componentConfig.tableName을 사용해야 함 (화면 테이블이 아닌 검색 대상 테이블)
// 🆕 v2-input도 포함 (채번 규칙 조회 시 tableName 필요)
const useConfigTableName =
componentType === "entity-search-input" ||
componentType === "autocomplete-search-input" ||
componentType === "modal-repeater-table";
componentType === "modal-repeater-table" ||
componentType === "v2-input";
const rendererProps = {
component,
@ -524,9 +526,21 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
componentConfig: component.componentConfig,
// componentConfig의 모든 속성을 props로 spread (tableName, displayField 등)
...(component.componentConfig || {}),
// 🆕 V2 레이아웃에서 overrides에서 복원된 상위 레벨 속성들도 전달
inputType: (component as any).inputType || component.componentConfig?.inputType,
columnName: (component as any).columnName || component.componentConfig?.columnName,
value: currentValue, // formData에서 추출한 현재 값 전달
// 새로운 기능들 전달
autoGeneration: component.autoGeneration || component.componentConfig?.autoGeneration,
// 🆕 webTypeConfig.numberingRuleId가 있으면 autoGeneration으로 변환
autoGeneration: component.autoGeneration ||
component.componentConfig?.autoGeneration ||
((component as any).webTypeConfig?.numberingRuleId ? {
type: "numbering_rule" as const,
enabled: true,
options: {
numberingRuleId: (component as any).webTypeConfig.numberingRuleId,
},
} : undefined),
hidden: hiddenValue,
// React 전용 props들은 직접 전달 (DOM에 전달되지 않음)
isInteractive,
@ -534,7 +548,10 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
onFormDataChange,
onChange: handleChange, // 개선된 onChange 핸들러 전달
// 🆕 엔티티 검색 컴포넌트는 componentConfig.tableName 유지, 그 외는 화면 테이블명 사용
tableName: useConfigTableName ? component.componentConfig?.tableName || tableName : tableName,
// 🆕 component.tableName도 확인 (V2 레이아웃에서 overrides.tableName이 복원됨)
tableName: useConfigTableName
? component.componentConfig?.tableName || (component as any).tableName || tableName
: tableName,
menuId, // 🆕 메뉴 ID
menuObjid, // 🆕 메뉴 OBJID (메뉴 스코프)
selectedScreen, // 🆕 화면 정보

View File

@ -3043,8 +3043,12 @@ export class ButtonActionExecutor {
}
// 4. 모달 열기 이벤트 발생
// passSelectedData가 true이면 editData로 전달 (수정 모드처럼 모든 필드 표시)
// 🔧 수정: openModalWithData는 "신규 등록 + 연결 데이터 전달"용이므로
// editData가 아닌 splitPanelParentData로 전달해야 채번 등이 정상 작동함
const isPassDataMode = passSelectedData && selectedData.length > 0;
// 🔧 isEditMode 옵션이 명시적으로 true인 경우에만 수정 모드로 처리
const useAsEditData = config.isEditMode === true;
const modalEvent = new CustomEvent("openScreenModal", {
detail: {
@ -3054,9 +3058,10 @@ export class ButtonActionExecutor {
size: config.modalSize || "md",
selectedData: selectedData,
selectedIds: selectedData.map((row: any) => row.id).filter(Boolean),
// 🆕 데이터 전달 모드일 때는 editData로 전달하여 모든 필드가 표시되도록 함
editData: isPassDataMode ? parentData : undefined,
splitPanelParentData: isPassDataMode ? undefined : parentData,
// 🔧 수정: isEditMode가 명시적으로 true인 경우에만 editData로 전달
// 기본적으로는 splitPanelParentData로 전달하여 신규 등록 + 연결 데이터 모드
editData: useAsEditData && isPassDataMode ? parentData : undefined,
splitPanelParentData: isPassDataMode ? parentData : undefined,
urlParams: dataSourceId ? { dataSourceId } : undefined,
},
});