fix: Improve number and slider input handling in V2Input and SplitPanelLayoutComponent
- Enhanced V2Input to convert string values from the database to numbers for number and slider inputs, ensuring correct display and functionality. - Updated primary key retrieval logic in SplitPanelLayoutComponent to prioritize actual DB id values, improving data integrity. - Simplified primary key handling by removing unnecessary checks and ensuring consistent usage of id fields. - Improved user feedback in the SplitPanelLayoutComponent with clearer console logs for save operations and item selections.
This commit is contained in:
parent
505930b3ec
commit
d0ebb82f90
|
|
@ -771,9 +771,15 @@ export const V2Input = forwardRef<HTMLDivElement, V2InputProps>((props, ref) =>
|
||||||
);
|
);
|
||||||
|
|
||||||
case "number":
|
case "number":
|
||||||
|
// DB에서 문자열("325")로 반환되는 경우도 숫자로 변환하여 표시
|
||||||
|
const numValue = typeof displayValue === "number"
|
||||||
|
? displayValue
|
||||||
|
: (displayValue !== undefined && displayValue !== null && displayValue !== "" && !isNaN(Number(displayValue)))
|
||||||
|
? Number(displayValue)
|
||||||
|
: undefined;
|
||||||
return (
|
return (
|
||||||
<NumberInput
|
<NumberInput
|
||||||
value={typeof displayValue === "number" ? displayValue : undefined}
|
value={numValue}
|
||||||
onChange={(v) => {
|
onChange={(v) => {
|
||||||
setAutoGeneratedValue(null);
|
setAutoGeneratedValue(null);
|
||||||
onChange?.(v ?? 0);
|
onChange?.(v ?? 0);
|
||||||
|
|
@ -802,9 +808,15 @@ export const V2Input = forwardRef<HTMLDivElement, V2InputProps>((props, ref) =>
|
||||||
);
|
);
|
||||||
|
|
||||||
case "slider":
|
case "slider":
|
||||||
|
// DB에서 문자열로 반환되는 경우도 숫자로 변환
|
||||||
|
const sliderValue = typeof displayValue === "number"
|
||||||
|
? displayValue
|
||||||
|
: (displayValue !== undefined && displayValue !== null && displayValue !== "" && !isNaN(Number(displayValue)))
|
||||||
|
? Number(displayValue)
|
||||||
|
: (config.min ?? 0);
|
||||||
return (
|
return (
|
||||||
<SliderInput
|
<SliderInput
|
||||||
value={typeof displayValue === "number" ? displayValue : (config.min ?? 0)}
|
value={sliderValue}
|
||||||
onChange={(v) => {
|
onChange={(v) => {
|
||||||
setAutoGeneratedValue(null);
|
setAutoGeneratedValue(null);
|
||||||
onChange?.(v);
|
onChange?.(v);
|
||||||
|
|
|
||||||
|
|
@ -2105,22 +2105,16 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
const editButtonConfig = componentConfig.leftPanel?.editButton;
|
const editButtonConfig = componentConfig.leftPanel?.editButton;
|
||||||
if (editButtonConfig?.mode === "modal" && editButtonConfig?.modalScreenId) {
|
if (editButtonConfig?.mode === "modal" && editButtonConfig?.modalScreenId) {
|
||||||
const leftTableName = componentConfig.leftPanel?.tableName || "";
|
const leftTableName = componentConfig.leftPanel?.tableName || "";
|
||||||
const sourceColumn = componentConfig.leftPanel?.itemAddConfig?.sourceColumn || "id";
|
|
||||||
|
|
||||||
// Primary Key 찾기
|
// Primary Key 찾기 - 실제 DB의 id 컬럼 값을 우선 사용
|
||||||
let primaryKeyName = sourceColumn;
|
let primaryKeyValue = item.id || item.ID;
|
||||||
let primaryKeyValue = item[sourceColumn];
|
|
||||||
|
|
||||||
if (primaryKeyValue === undefined || primaryKeyValue === null) {
|
if (primaryKeyValue === undefined || primaryKeyValue === null) {
|
||||||
if (item.id !== undefined && item.id !== null) {
|
// id가 없으면 sourceColumn 시도, 마지막으로 첫 번째 키
|
||||||
primaryKeyName = "id";
|
const sourceColumn = componentConfig.leftPanel?.itemAddConfig?.sourceColumn || "id";
|
||||||
primaryKeyValue = item.id;
|
primaryKeyValue = item[sourceColumn];
|
||||||
} else if (item.ID !== undefined && item.ID !== null) {
|
if (primaryKeyValue === undefined || primaryKeyValue === null) {
|
||||||
primaryKeyName = "ID";
|
|
||||||
primaryKeyValue = item.ID;
|
|
||||||
} else {
|
|
||||||
const firstKey = Object.keys(item)[0];
|
const firstKey = Object.keys(item)[0];
|
||||||
primaryKeyName = firstKey;
|
|
||||||
primaryKeyValue = item[firstKey];
|
primaryKeyValue = item[firstKey];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2147,7 +2141,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
console.log("✅ [SplitPanel] 좌측 수정 모달 화면 열기:", {
|
console.log("✅ [SplitPanel] 좌측 수정 모달 화면 열기:", {
|
||||||
screenId: editButtonConfig.modalScreenId,
|
screenId: editButtonConfig.modalScreenId,
|
||||||
tableName: leftTableName,
|
tableName: leftTableName,
|
||||||
primaryKeyName,
|
|
||||||
primaryKeyValue,
|
primaryKeyValue,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
|
@ -2282,9 +2275,8 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Primary Key 찾기
|
// Primary Key 찾기 - 실제 DB의 id 컬럼 값을 사용 (sourceColumn은 관계 연결용이므로 PK로 사용하지 않음)
|
||||||
const sourceColumn = componentConfig.leftPanel?.itemAddConfig?.sourceColumn || "id";
|
const primaryKey = selectedLeftItem.id || selectedLeftItem.ID;
|
||||||
const primaryKey = selectedLeftItem[sourceColumn] || selectedLeftItem.id || selectedLeftItem.ID;
|
|
||||||
|
|
||||||
if (!primaryKey) {
|
if (!primaryKey) {
|
||||||
toast({
|
toast({
|
||||||
|
|
@ -2307,7 +2299,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
cleanData.company_code = companyCode;
|
cleanData.company_code = companyCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("📝 [SplitPanel] 커스텀 우측 패널 저장:", { tableName, sourceColumn, primaryKey, data: cleanData });
|
console.log("📝 [SplitPanel] 커스텀 우측 패널 저장:", { tableName, primaryKey, data: cleanData });
|
||||||
|
|
||||||
const response = await dataApi.updateRecord(tableName, primaryKey, cleanData);
|
const response = await dataApi.updateRecord(tableName, primaryKey, cleanData);
|
||||||
|
|
||||||
|
|
@ -2529,7 +2521,8 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
if (deleteModalPanel === "left") {
|
if (deleteModalPanel === "left") {
|
||||||
loadLeftData();
|
loadLeftData();
|
||||||
// 삭제된 항목이 선택되어 있었으면 선택 해제
|
// 삭제된 항목이 선택되어 있었으면 선택 해제
|
||||||
if (selectedLeftItem && selectedLeftItem[sourceColumn] === primaryKey) {
|
const deletedId = deleteModalItem?.id || deleteModalItem?.ID;
|
||||||
|
if (selectedLeftItem && (selectedLeftItem.id === deletedId || selectedLeftItem.ID === deletedId)) {
|
||||||
setSelectedLeftItem(null);
|
setSelectedLeftItem(null);
|
||||||
setRightData(null);
|
setRightData(null);
|
||||||
}
|
}
|
||||||
|
|
@ -2968,6 +2961,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
const displayHeight = isResizingComp && resizeSize ? resizeSize.height : (comp.size?.height || 100);
|
const displayHeight = isResizingComp && resizeSize ? resizeSize.height : (comp.size?.height || 100);
|
||||||
|
|
||||||
// 컴포넌트 데이터를 DynamicComponentRenderer 형식으로 변환
|
// 컴포넌트 데이터를 DynamicComponentRenderer 형식으로 변환
|
||||||
|
// componentConfig의 주요 속성을 최상위로 펼침 (일반 화면의 overrides 플래트닝과 동일)
|
||||||
const componentData = {
|
const componentData = {
|
||||||
id: comp.id,
|
id: comp.id,
|
||||||
type: "component" as const,
|
type: "component" as const,
|
||||||
|
|
@ -2977,6 +2971,11 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
size: { width: displayWidth, height: displayHeight },
|
size: { width: displayWidth, height: displayHeight },
|
||||||
componentConfig: comp.componentConfig || {},
|
componentConfig: comp.componentConfig || {},
|
||||||
style: comp.style || {},
|
style: comp.style || {},
|
||||||
|
// 파일 업로드/미디어 등이 component.tableName, component.columnName을 직접 참조하므로 펼침
|
||||||
|
tableName: comp.componentConfig?.tableName,
|
||||||
|
columnName: comp.componentConfig?.columnName,
|
||||||
|
webType: comp.componentConfig?.webType,
|
||||||
|
inputType: comp.inputType || comp.componentConfig?.inputType,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isDesignMode) {
|
if (isDesignMode) {
|
||||||
|
|
@ -3981,6 +3980,15 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
})()
|
})()
|
||||||
) : componentConfig.rightPanel?.displayMode === "custom" ? (
|
) : componentConfig.rightPanel?.displayMode === "custom" ? (
|
||||||
// 🆕 커스텀 모드: 패널 안에 자유롭게 컴포넌트 배치
|
// 🆕 커스텀 모드: 패널 안에 자유롭게 컴포넌트 배치
|
||||||
|
// 실행 모드에서 좌측 미선택 시 안내 메시지 표시
|
||||||
|
!isDesignMode && !selectedLeftItem ? (
|
||||||
|
<div className="flex h-full items-center justify-center">
|
||||||
|
<div className="text-muted-foreground text-center text-sm">
|
||||||
|
<p className="mb-2">좌측에서 항목을 선택하세요</p>
|
||||||
|
<p className="text-xs">선택한 항목의 상세 정보가 여기에 표시됩니다</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
<div
|
<div
|
||||||
className="relative h-full w-full"
|
className="relative h-full w-full"
|
||||||
data-split-panel-container="true"
|
data-split-panel-container="true"
|
||||||
|
|
@ -4002,6 +4010,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
const displayHeight = isResizingComp && resizeSize ? resizeSize.height : (comp.size?.height || 100);
|
const displayHeight = isResizingComp && resizeSize ? resizeSize.height : (comp.size?.height || 100);
|
||||||
|
|
||||||
// 컴포넌트 데이터를 DynamicComponentRenderer 형식으로 변환
|
// 컴포넌트 데이터를 DynamicComponentRenderer 형식으로 변환
|
||||||
|
// componentConfig의 주요 속성을 최상위로 펼침 (일반 화면의 overrides 플래트닝과 동일)
|
||||||
const componentData = {
|
const componentData = {
|
||||||
id: comp.id,
|
id: comp.id,
|
||||||
type: "component" as const,
|
type: "component" as const,
|
||||||
|
|
@ -4011,6 +4020,11 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
size: { width: displayWidth, height: displayHeight },
|
size: { width: displayWidth, height: displayHeight },
|
||||||
componentConfig: comp.componentConfig || {},
|
componentConfig: comp.componentConfig || {},
|
||||||
style: comp.style || {},
|
style: comp.style || {},
|
||||||
|
// 파일 업로드/미디어 등이 component.tableName, component.columnName을 직접 참조하므로 펼침
|
||||||
|
tableName: comp.componentConfig?.tableName,
|
||||||
|
columnName: comp.componentConfig?.columnName,
|
||||||
|
webType: comp.componentConfig?.webType,
|
||||||
|
inputType: comp.inputType || comp.componentConfig?.inputType,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isDesignMode) {
|
if (isDesignMode) {
|
||||||
|
|
@ -4201,6 +4215,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
) : isLoadingRight ? (
|
) : isLoadingRight ? (
|
||||||
// 로딩 중
|
// 로딩 중
|
||||||
<div className="flex h-full items-center justify-center">
|
<div className="flex h-full items-center justify-center">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue