[agent-pipeline] pipe-20260317063830-0nfs round-3
This commit is contained in:
parent
265f46f8d4
commit
9409f1308f
|
|
@ -26,7 +26,7 @@ export const NumberingRuleCard: React.FC<NumberingRuleCardProps> = ({
|
||||||
tableName,
|
tableName,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="config-field flex-1 rounded-lg border border-border bg-muted/50 p-3 sm:p-4">
|
<div className="config-field flex-1 rounded-[8px] border border-border bg-muted/50 px-3 py-3 sm:px-4 sm:py-4">
|
||||||
<div className="mb-3 flex items-center justify-between sm:mb-4">
|
<div className="mb-3 flex items-center justify-between sm:mb-4">
|
||||||
<Badge variant="outline" className="text-xs sm:text-sm">
|
<Badge variant="outline" className="text-xs sm:text-sm">
|
||||||
규칙 {part.order}
|
규칙 {part.order}
|
||||||
|
|
|
||||||
|
|
@ -404,7 +404,7 @@ export const NumberingRuleDesigner: React.FC<NumberingRuleDesignerProps> = ({
|
||||||
})}
|
})}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="pipe-add flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-[10px] border-2 border-dashed border-border text-muted-foreground transition-colors hover:border-primary hover:bg-primary/5 hover:text-primary"
|
className="pipe-add flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full border-2 border-dashed border-border text-muted-foreground transition-colors hover:border-primary hover:bg-primary/5 hover:text-primary"
|
||||||
onClick={handleAddPart}
|
onClick={handleAddPart}
|
||||||
disabled={currentRule.parts.length >= maxRules || isPreview || loading}
|
disabled={currentRule.parts.length >= maxRules || isPreview || loading}
|
||||||
aria-label="규칙 추가"
|
aria-label="규칙 추가"
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ export const NumberingRulePreview: React.FC<NumberingRulePreviewProps> = ({
|
||||||
if (variant === "strip") {
|
if (variant === "strip") {
|
||||||
const globalSep = config.separator ?? "-";
|
const globalSep = config.separator ?? "-";
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg bg-gradient-to-b from-muted to-card px-4 py-4 sm:px-6 sm:py-5">
|
<div className="rounded-lg border border-border bg-gradient-to-b from-muted to-card px-4 py-4 sm:px-6 sm:py-5">
|
||||||
<div className="font-mono text-[22px] font-extrabold tracking-tight sm:text-[28px]">
|
<div className="font-mono text-[22px] font-extrabold tracking-tight sm:text-[28px]">
|
||||||
{partItems.length === 0 ? (
|
{partItems.length === 0 ? (
|
||||||
<span className="text-muted-foreground">규칙을 추가해주세요</span>
|
<span className="text-muted-foreground">규칙을 추가해주세요</span>
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ interface CategoryValueManagerProps {
|
||||||
columnLabel: string;
|
columnLabel: string;
|
||||||
onValueCountChange?: (count: number) => void;
|
onValueCountChange?: (count: number) => void;
|
||||||
menuObjid?: number; // 현재 메뉴 OBJID (메뉴 스코프)
|
menuObjid?: number; // 현재 메뉴 OBJID (메뉴 스코프)
|
||||||
|
/** 편집기 헤더 오른쪽에 표시할 내용 (예: 트리/목록 세그먼트) */
|
||||||
|
headerRight?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CategoryValueManager: React.FC<CategoryValueManagerProps> = ({
|
export const CategoryValueManager: React.FC<CategoryValueManagerProps> = ({
|
||||||
|
|
@ -38,6 +40,7 @@ export const CategoryValueManager: React.FC<CategoryValueManagerProps> = ({
|
||||||
columnLabel,
|
columnLabel,
|
||||||
onValueCountChange,
|
onValueCountChange,
|
||||||
menuObjid,
|
menuObjid,
|
||||||
|
headerRight,
|
||||||
}) => {
|
}) => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const [values, setValues] = useState<TableCategoryValue[]>([]);
|
const [values, setValues] = useState<TableCategoryValue[]>([]);
|
||||||
|
|
@ -284,7 +287,7 @@ export const CategoryValueManager: React.FC<CategoryValueManagerProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
{/* 헤더 */}
|
{/* 편집기 헤더: 컬럼명 + 값 수 + 비활성 토글 + 새 값 추가 + headerRight(트리·목록 세그먼트 등) */}
|
||||||
<div className="border-b p-4">
|
<div className="border-b p-4">
|
||||||
<div className="mb-4 flex items-center justify-between">
|
<div className="mb-4 flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -308,11 +311,11 @@ export const CategoryValueManager: React.FC<CategoryValueManagerProps> = ({
|
||||||
비활성 항목 표시
|
비활성 항목 표시
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button onClick={() => setIsAddDialogOpen(true)} size="sm">
|
<Button onClick={() => setIsAddDialogOpen(true)} size="sm">
|
||||||
<Plus className="mr-2 h-4 w-4" />
|
<Plus className="mr-2 h-4 w-4" />
|
||||||
새 값 추가
|
새 값 추가
|
||||||
</Button>
|
</Button>
|
||||||
|
{headerRight != null ? <div className="flex items-center">{headerRight}</div> : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,8 @@ interface CategoryValueManagerTreeProps {
|
||||||
columnName: string;
|
columnName: string;
|
||||||
columnLabel: string;
|
columnLabel: string;
|
||||||
onValueCountChange?: (count: number) => void;
|
onValueCountChange?: (count: number) => void;
|
||||||
|
/** 편집기 헤더 오른쪽에 표시할 내용 (예: 트리/목록 세그먼트) */
|
||||||
|
headerRight?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 트리 노드 컴포넌트
|
// 트리 노드 컴포넌트
|
||||||
|
|
@ -272,6 +274,7 @@ export const CategoryValueManagerTree: React.FC<CategoryValueManagerTreeProps> =
|
||||||
columnName,
|
columnName,
|
||||||
columnLabel,
|
columnLabel,
|
||||||
onValueCountChange,
|
onValueCountChange,
|
||||||
|
headerRight,
|
||||||
}) => {
|
}) => {
|
||||||
// 상태
|
// 상태
|
||||||
const [tree, setTree] = useState<CategoryValue[]>([]);
|
const [tree, setTree] = useState<CategoryValue[]>([]);
|
||||||
|
|
@ -634,7 +637,7 @@ export const CategoryValueManagerTree: React.FC<CategoryValueManagerTreeProps> =
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
{/* 편집기 헤더: 컬럼명 + 값 수 Badge + 선택 Badge + 액션 버튼 */}
|
{/* 편집기 헤더: 컬럼명 + 값 수 Badge + 비활성/전체펼침/대분류추가 + headerRight(트리·목록 세그먼트 등) */}
|
||||||
<div className="mb-3 flex items-center justify-between border-b pb-3">
|
<div className="mb-3 flex items-center justify-between border-b pb-3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<h3 className="text-base font-semibold">{columnLabel} 카테고리</h3>
|
<h3 className="text-base font-semibold">{columnLabel} 카테고리</h3>
|
||||||
|
|
@ -668,6 +671,7 @@ export const CategoryValueManagerTree: React.FC<CategoryValueManagerTreeProps> =
|
||||||
<Plus className="h-3.5 w-3.5" />
|
<Plus className="h-3.5 w-3.5" />
|
||||||
대분류 추가
|
대분류 추가
|
||||||
</Button>
|
</Button>
|
||||||
|
{headerRight != null ? <div className="flex items-center">{headerRight}</div> : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,33 +88,33 @@ export function V2CategoryManagerComponent({
|
||||||
[columns, selectedTable],
|
[columns, selectedTable],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** 편집기 헤더에 표시할 트리/목록 세그먼트 (보기 방식 토글) */
|
||||||
|
const viewModeSegment =
|
||||||
|
config.showViewModeToggle ? (
|
||||||
|
<div className="flex rounded-md border p-0.5">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className={cn("h-7 gap-1.5 px-2.5 text-xs", viewMode === "tree" && "bg-accent")}
|
||||||
|
onClick={() => setViewMode("tree")}
|
||||||
|
>
|
||||||
|
<TreeDeciduous className="h-3.5 w-3.5" />
|
||||||
|
트리
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className={cn("h-7 gap-1.5 px-2.5 text-xs", viewMode === "list" && "bg-accent")}
|
||||||
|
onClick={() => setViewMode("list")}
|
||||||
|
>
|
||||||
|
<LayoutList className="h-3.5 w-3.5" />
|
||||||
|
목록
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : null;
|
||||||
|
|
||||||
const rightContent = (
|
const rightContent = (
|
||||||
<>
|
<>
|
||||||
{config.showViewModeToggle && (
|
|
||||||
<div className="mb-2 flex items-center justify-end gap-1">
|
|
||||||
<span className="text-muted-foreground mr-2 text-xs">보기 방식:</span>
|
|
||||||
<div className="flex rounded-md border p-0.5">
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
className={cn("h-7 gap-1.5 px-2.5 text-xs", viewMode === "tree" && "bg-accent")}
|
|
||||||
onClick={() => setViewMode("tree")}
|
|
||||||
>
|
|
||||||
<TreeDeciduous className="h-3.5 w-3.5" />
|
|
||||||
트리
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
className={cn("h-7 gap-1.5 px-2.5 text-xs", viewMode === "list" && "bg-accent")}
|
|
||||||
onClick={() => setViewMode("list")}
|
|
||||||
>
|
|
||||||
<LayoutList className="h-3.5 w-3.5" />
|
|
||||||
목록
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="min-h-0 flex-1 overflow-y-auto">
|
<div className="min-h-0 flex-1 overflow-y-auto">
|
||||||
{selectedColumn ? (
|
{selectedColumn ? (
|
||||||
viewMode === "tree" ? (
|
viewMode === "tree" ? (
|
||||||
|
|
@ -123,6 +123,7 @@ export function V2CategoryManagerComponent({
|
||||||
tableName={selectedColumn.tableName}
|
tableName={selectedColumn.tableName}
|
||||||
columnName={selectedColumn.columnName}
|
columnName={selectedColumn.columnName}
|
||||||
columnLabel={selectedColumn.columnLabel}
|
columnLabel={selectedColumn.columnLabel}
|
||||||
|
headerRight={viewModeSegment}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<CategoryValueManager
|
<CategoryValueManager
|
||||||
|
|
@ -131,6 +132,7 @@ export function V2CategoryManagerComponent({
|
||||||
columnName={selectedColumn.columnName}
|
columnName={selectedColumn.columnName}
|
||||||
columnLabel={selectedColumn.columnLabel}
|
columnLabel={selectedColumn.columnLabel}
|
||||||
menuObjid={effectiveMenuObjid}
|
menuObjid={effectiveMenuObjid}
|
||||||
|
headerRight={viewModeSegment}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
|
|
@ -207,19 +207,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}) => {
|
}) => {
|
||||||
const componentConfig = (component.componentConfig || {}) as SplitPanelLayoutConfig;
|
const componentConfig = (component.componentConfig || {}) as SplitPanelLayoutConfig;
|
||||||
|
|
||||||
// 🐛 디버깅: 로드 시 rightPanel.components 확인
|
|
||||||
const rightComps = componentConfig.rightPanel?.components || [];
|
|
||||||
const finishedTimeline = rightComps.find((c: any) => c.id === "finished_timeline");
|
|
||||||
if (finishedTimeline) {
|
|
||||||
const fm = finishedTimeline.componentConfig?.fieldMapping;
|
|
||||||
console.log("🔍 [SplitPanelLayout] finished_timeline fieldMapping:", {
|
|
||||||
componentId: finishedTimeline.id,
|
|
||||||
fieldMapping: fm ? JSON.stringify(fm) : "undefined",
|
|
||||||
fieldMappingKeys: fm ? Object.keys(fm) : [],
|
|
||||||
fieldMappingId: fm?.id,
|
|
||||||
fullComponentConfig: JSON.stringify(finishedTimeline.componentConfig || {}, null, 2),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 🆕 프리뷰용 회사 코드 오버라이드 (최고 관리자만 사용 가능)
|
// 🆕 프리뷰용 회사 코드 오버라이드 (최고 관리자만 사용 가능)
|
||||||
const companyCode = (props as any).companyCode as string | undefined;
|
const companyCode = (props as any).companyCode as string | undefined;
|
||||||
|
|
||||||
|
|
@ -635,14 +622,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
} = splitPanelContext;
|
} = splitPanelContext;
|
||||||
const splitPanelId = `split-panel-${component.id}`;
|
const splitPanelId = `split-panel-${component.id}`;
|
||||||
|
|
||||||
// 디버깅: Context 연결 상태 확인
|
|
||||||
console.log("🔗 [SplitPanelLayout] Context 연결 상태:", {
|
|
||||||
componentId: component.id,
|
|
||||||
splitPanelId,
|
|
||||||
hasRegisterFunc: typeof ctxRegisterSplitPanel === "function",
|
|
||||||
splitPanelsSize: splitPanelContext.splitPanels?.size ?? "없음",
|
|
||||||
});
|
|
||||||
|
|
||||||
// Context에 분할 패널 등록 (좌표 정보 포함) - 마운트 시 1회만 실행
|
// Context에 분할 패널 등록 (좌표 정보 포함) - 마운트 시 1회만 실행
|
||||||
const ctxRegisterRef = useRef(ctxRegisterSplitPanel);
|
const ctxRegisterRef = useRef(ctxRegisterSplitPanel);
|
||||||
const ctxUnregisterRef = useRef(ctxUnregisterSplitPanel);
|
const ctxUnregisterRef = useRef(ctxUnregisterSplitPanel);
|
||||||
|
|
@ -666,15 +645,9 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("📦 [SplitPanelLayout] Context에 분할 패널 등록:", {
|
|
||||||
splitPanelId,
|
|
||||||
panelInfo,
|
|
||||||
});
|
|
||||||
|
|
||||||
ctxRegisterRef.current(splitPanelId, panelInfo);
|
ctxRegisterRef.current(splitPanelId, panelInfo);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
console.log("📦 [SplitPanelLayout] Context에서 분할 패널 해제:", splitPanelId);
|
|
||||||
ctxUnregisterRef.current(splitPanelId);
|
ctxUnregisterRef.current(splitPanelId);
|
||||||
};
|
};
|
||||||
// 마운트/언마운트 시에만 실행, 위치/크기 변경은 별도 업데이트로 처리
|
// 마운트/언마운트 시에만 실행, 위치/크기 변경은 별도 업데이트로 처리
|
||||||
|
|
@ -731,10 +704,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
initialLeftWidthPercent: leftWidth,
|
initialLeftWidthPercent: leftWidth,
|
||||||
});
|
});
|
||||||
console.log("🛑 [SplitPanelLayout] 드래그 종료 - 버튼 위치 고정:", {
|
|
||||||
splitPanelId,
|
|
||||||
finalLeftWidthPercent: leftWidth,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prevIsDraggingRef.current = isDragging;
|
prevIsDraggingRef.current = isDragging;
|
||||||
|
|
@ -742,11 +711,8 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
|
|
||||||
// 🆕 그룹별 합산된 데이터 계산
|
// 🆕 그룹별 합산된 데이터 계산
|
||||||
const summedLeftData = useMemo(() => {
|
const summedLeftData = useMemo(() => {
|
||||||
console.log("🔍 [그룹합산] leftGroupSumConfig:", leftGroupSumConfig);
|
|
||||||
|
|
||||||
// 그룹핑이 비활성화되었거나 그룹 기준 컬럼이 없으면 원본 데이터 반환
|
// 그룹핑이 비활성화되었거나 그룹 기준 컬럼이 없으면 원본 데이터 반환
|
||||||
if (!leftGroupSumConfig?.enabled || !leftGroupSumConfig?.groupByColumn) {
|
if (!leftGroupSumConfig?.enabled || !leftGroupSumConfig?.groupByColumn) {
|
||||||
console.log("🔍 [그룹합산] 그룹핑 비활성화 - 원본 데이터 반환");
|
|
||||||
return leftData;
|
return leftData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -759,7 +725,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
const [refTable, fieldName] = columnName.split(".");
|
const [refTable, fieldName] = columnName.split(".");
|
||||||
const inferredSourceColumn = refTable.replace("_info", "_code").replace("_mng", "_id");
|
const inferredSourceColumn = refTable.replace("_info", "_code").replace("_mng", "_id");
|
||||||
const exactKey = `${inferredSourceColumn}_${fieldName}`;
|
const exactKey = `${inferredSourceColumn}_${fieldName}`;
|
||||||
console.log("🔍 [그룹합산] 조인 컬럼 키 변환:", { columnName, exactKey, hasKey: item[exactKey] !== undefined });
|
|
||||||
if (item[exactKey] !== undefined) return exactKey;
|
if (item[exactKey] !== undefined) return exactKey;
|
||||||
if (fieldName === "item_name" || fieldName === "name") {
|
if (fieldName === "item_name" || fieldName === "name") {
|
||||||
const aliasKey = `${inferredSourceColumn}_name`;
|
const aliasKey = `${inferredSourceColumn}_name`;
|
||||||
|
|
@ -812,14 +777,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = Array.from(groupMap.values());
|
return Array.from(groupMap.values());
|
||||||
console.log("🔗 [분할패널] 그룹별 합산 결과:", {
|
|
||||||
원본개수: leftData.length,
|
|
||||||
그룹개수: result.length,
|
|
||||||
그룹기준: groupByColumn,
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}, [leftData, leftGroupSumConfig]);
|
}, [leftData, leftGroupSumConfig]);
|
||||||
|
|
||||||
// 컴포넌트 스타일
|
// 컴포넌트 스타일
|
||||||
|
|
@ -1262,8 +1220,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
leftTableName,
|
leftTableName,
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("🔗 [분할패널] 좌측 additionalJoinColumns:", leftJoinColumns);
|
|
||||||
|
|
||||||
const result = await entityJoinApi.getTableDataWithJoins(leftTableName, {
|
const result = await entityJoinApi.getTableDataWithJoins(leftTableName, {
|
||||||
page: 1,
|
page: 1,
|
||||||
size: 100,
|
size: 100,
|
||||||
|
|
@ -1274,12 +1230,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
companyCodeOverride: companyCode,
|
companyCodeOverride: companyCode,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 🔍 디버깅: API 응답 데이터의 키 확인
|
|
||||||
if (result.data && result.data.length > 0) {
|
|
||||||
console.log("🔗 [분할패널] API 응답 첫 번째 데이터 키:", Object.keys(result.data[0]));
|
|
||||||
console.log("🔗 [분할패널] API 응답 첫 번째 데이터:", result.data[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 좌측 패널 dataFilter 클라이언트 사이드 적용
|
// 좌측 패널 dataFilter 클라이언트 사이드 적용
|
||||||
let filteredLeftData = result.data || [];
|
let filteredLeftData = result.data || [];
|
||||||
const leftDataFilter = componentConfig.leftPanel?.dataFilter;
|
const leftDataFilter = componentConfig.leftPanel?.dataFilter;
|
||||||
|
|
@ -1453,11 +1403,8 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
|
|
||||||
// 🆕 그룹 합산된 항목인 경우: 원본 데이터들로 우측 패널 표시
|
// 🆕 그룹 합산된 항목인 경우: 원본 데이터들로 우측 패널 표시
|
||||||
if (leftItem._originalItems && leftItem._originalItems.length > 0) {
|
if (leftItem._originalItems && leftItem._originalItems.length > 0) {
|
||||||
console.log("🔗 [분할패널] 그룹 합산 항목 - 원본 개수:", leftItem._originalItems.length);
|
|
||||||
|
|
||||||
// 정렬 기준 컬럼 (복합키의 leftColumn들)
|
// 정렬 기준 컬럼 (복합키의 leftColumn들)
|
||||||
const sortColumns = keys?.map((k: any) => k.leftColumn).filter(Boolean) || [];
|
const sortColumns = keys?.map((k: any) => k.leftColumn).filter(Boolean) || [];
|
||||||
console.log("🔗 [분할패널] 정렬 기준 컬럼:", sortColumns);
|
|
||||||
|
|
||||||
// 정렬 함수
|
// 정렬 함수
|
||||||
const sortByKeys = (data: any[]) => {
|
const sortByKeys = (data: any[]) => {
|
||||||
|
|
@ -1476,7 +1423,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
// 원본 데이터를 그대로 우측 패널에 표시 (이력 테이블과 동일 테이블인 경우)
|
// 원본 데이터를 그대로 우측 패널에 표시 (이력 테이블과 동일 테이블인 경우)
|
||||||
if (leftTable === rightTableName) {
|
if (leftTable === rightTableName) {
|
||||||
const sortedData = sortByKeys(leftItem._originalItems);
|
const sortedData = sortByKeys(leftItem._originalItems);
|
||||||
console.log("🔗 [분할패널] 동일 테이블 - 정렬된 원본 데이터:", sortedData.length);
|
|
||||||
setRightData(sortedData);
|
setRightData(sortedData);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1514,9 +1460,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 정렬 적용
|
|
||||||
const sortedResults = sortByKeys(allResults);
|
const sortedResults = sortByKeys(allResults);
|
||||||
console.log("🔗 [분할패널] 그룹 합산 - 우측 패널 정렬된 데이터:", sortedResults.length);
|
|
||||||
setRightData(sortedResults);
|
setRightData(sortedResults);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1534,17 +1478,11 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("🔗 [분할패널] 복합키 조건:", searchConditions);
|
|
||||||
|
|
||||||
// 🆕 우측 패널 config의 Entity 조인 컬럼 추출
|
// 🆕 우측 패널 config의 Entity 조인 컬럼 추출
|
||||||
const rightJoinColumns = extractAdditionalJoinColumns(
|
const rightJoinColumns = extractAdditionalJoinColumns(
|
||||||
componentConfig.rightPanel?.columns,
|
componentConfig.rightPanel?.columns,
|
||||||
rightTableName,
|
rightTableName,
|
||||||
);
|
);
|
||||||
if (rightJoinColumns) {
|
|
||||||
console.log("🔗 [분할패널] 우측 패널 additionalJoinColumns:", rightJoinColumns);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 엔티티 조인 API로 데이터 조회
|
// 엔티티 조인 API로 데이터 조회
|
||||||
const result = await entityJoinApi.getTableDataWithJoins(rightTableName, {
|
const result = await entityJoinApi.getTableDataWithJoins(rightTableName, {
|
||||||
search: searchConditions,
|
search: searchConditions,
|
||||||
|
|
@ -1554,8 +1492,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
additionalJoinColumns: rightJoinColumns,
|
additionalJoinColumns: rightJoinColumns,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("🔗 [분할패널] 복합키 조회 결과:", result);
|
|
||||||
|
|
||||||
setRightData(result.data || []);
|
setRightData(result.data || []);
|
||||||
} else {
|
} else {
|
||||||
// 단일키 (하위 호환성) → entityJoinApi 사용으로 전환 (entity 조인 컬럼 지원)
|
// 단일키 (하위 호환성) → entityJoinApi 사용으로 전환 (entity 조인 컬럼 지원)
|
||||||
|
|
@ -1566,8 +1502,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
const leftValue = leftItem[leftColumn];
|
const leftValue = leftItem[leftColumn];
|
||||||
const { entityJoinApi } = await import("@/lib/api/entityJoin");
|
const { entityJoinApi } = await import("@/lib/api/entityJoin");
|
||||||
|
|
||||||
console.log("🔗 [분할패널] 단일키 조건:", { leftColumn, rightColumn, leftValue, rightTableName });
|
|
||||||
|
|
||||||
// 단일키를 복합키 형식으로 변환 (entity 컬럼이므로 equals 연산자 필수)
|
// 단일키를 복합키 형식으로 변환 (entity 컬럼이므로 equals 연산자 필수)
|
||||||
const searchConditions: Record<string, any> = {};
|
const searchConditions: Record<string, any> = {};
|
||||||
searchConditions[rightColumn] = { value: leftValue, operator: "equals" };
|
searchConditions[rightColumn] = { value: leftValue, operator: "equals" };
|
||||||
|
|
@ -1577,10 +1511,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
componentConfig.rightPanel?.columns,
|
componentConfig.rightPanel?.columns,
|
||||||
rightTableName,
|
rightTableName,
|
||||||
);
|
);
|
||||||
if (rightJoinColumnsLegacy) {
|
|
||||||
console.log("🔗 [분할패널] 단일키 모드 additionalJoinColumns:", rightJoinColumnsLegacy);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await entityJoinApi.getTableDataWithJoins(rightTableName, {
|
const result = await entityJoinApi.getTableDataWithJoins(rightTableName, {
|
||||||
search: searchConditions,
|
search: searchConditions,
|
||||||
enableEntityJoin: true,
|
enableEntityJoin: true,
|
||||||
|
|
@ -1631,10 +1561,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
|
|
||||||
// 탭 config의 Entity 조인 컬럼 추출
|
// 탭 config의 Entity 조인 컬럼 추출
|
||||||
const tabJoinColumns = extractAdditionalJoinColumns(tabConfig.columns, tabTableName);
|
const tabJoinColumns = extractAdditionalJoinColumns(tabConfig.columns, tabTableName);
|
||||||
if (tabJoinColumns) {
|
|
||||||
console.log(`🔗 [분할패널] 탭 ${tabIndex} additionalJoinColumns:`, tabJoinColumns);
|
|
||||||
}
|
|
||||||
|
|
||||||
let resultData: any[] = [];
|
let resultData: any[] = [];
|
||||||
|
|
||||||
// 탭의 dataFilter (API 전달용)
|
// 탭의 dataFilter (API 전달용)
|
||||||
|
|
@ -1830,7 +1756,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
if (leftTableName && !isDesignMode) {
|
if (leftTableName && !isDesignMode) {
|
||||||
import("@/stores/modalDataStore").then(({ useModalDataStore }) => {
|
import("@/stores/modalDataStore").then(({ useModalDataStore }) => {
|
||||||
useModalDataStore.getState().setData(leftTableName, [item]);
|
useModalDataStore.getState().setData(leftTableName, [item]);
|
||||||
console.log(`✅ 분할 패널 좌측 선택: ${leftTableName}`, item);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -2051,7 +1976,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setLeftColumnLabels(labels);
|
setLeftColumnLabels(labels);
|
||||||
console.log("✅ 좌측 컬럼 라벨 로드:", labels);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("좌측 테이블 컬럼 라벨 로드 실패:", error);
|
console.error("좌측 테이블 컬럼 라벨 로드 실패:", error);
|
||||||
}
|
}
|
||||||
|
|
@ -2214,8 +2138,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("🔍 우측 패널 카테고리 로드 대상 테이블:", Array.from(tablesToLoad));
|
|
||||||
|
|
||||||
// 각 테이블에 대해 카테고리 매핑 로드
|
// 각 테이블에 대해 카테고리 매핑 로드
|
||||||
for (const tableName of tablesToLoad) {
|
for (const tableName of tablesToLoad) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -2245,9 +2167,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
// 🆕 컬럼명만으로도 접근할 수 있도록 추가 저장 (모든 테이블)
|
// 🆕 컬럼명만으로도 접근할 수 있도록 추가 저장 (모든 테이블)
|
||||||
// 기존 매핑이 있으면 병합, 없으면 새로 생성
|
// 기존 매핑이 있으면 병합, 없으면 새로 생성
|
||||||
mappings[columnName] = { ...(mappings[columnName] || {}), ...valueMap };
|
mappings[columnName] = { ...(mappings[columnName] || {}), ...valueMap };
|
||||||
|
|
||||||
console.log(`✅ 우측 카테고리 매핑 로드 [${mappingKey}]:`, valueMap);
|
|
||||||
console.log(`✅ 우측 카테고리 매핑 (컬럼명만) [${columnName}]:`, mappings[columnName]);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`우측 카테고리 값 조회 실패 [${tableName}.${columnName}]:`, error);
|
console.error(`우측 카테고리 값 조회 실패 [${tableName}.${columnName}]:`, error);
|
||||||
|
|
@ -2302,10 +2221,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("✅ [SplitPanel] 좌측 추가 모달 화면 열기:", {
|
|
||||||
screenId: addButtonConfig.modalScreenId,
|
|
||||||
tableName: leftTableName,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2372,11 +2287,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("✅ [SplitPanel] 추가 모달 화면 열기:", {
|
|
||||||
screenId: addButtonConfig.modalScreenId,
|
|
||||||
tableName: currentTableName,
|
|
||||||
parentData,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2445,11 +2355,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("✅ [SplitPanel] 좌측 수정 모달 화면 열기:", {
|
|
||||||
screenId: editButtonConfig.modalScreenId,
|
|
||||||
tableName: leftTableName,
|
|
||||||
primaryKeyValue,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2501,14 +2406,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("✅ 수정 모달 열기:", {
|
|
||||||
tableName: rightTableName,
|
|
||||||
primaryKeyName,
|
|
||||||
primaryKeyValue,
|
|
||||||
screenId: modalScreenId,
|
|
||||||
fullItem: item,
|
|
||||||
});
|
|
||||||
|
|
||||||
// modalDataStore에도 저장 (호환성 유지)
|
// modalDataStore에도 저장 (호환성 유지)
|
||||||
import("@/stores/modalDataStore").then(({ useModalDataStore }) => {
|
import("@/stores/modalDataStore").then(({ useModalDataStore }) => {
|
||||||
useModalDataStore.getState().setData(rightTableName, [item]);
|
useModalDataStore.getState().setData(rightTableName, [item]);
|
||||||
|
|
@ -2517,12 +2414,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
// 🆕 groupByColumns 추출
|
// 🆕 groupByColumns 추출
|
||||||
const groupByColumns = componentConfig.rightPanel?.editButton?.groupByColumns || [];
|
const groupByColumns = componentConfig.rightPanel?.editButton?.groupByColumns || [];
|
||||||
|
|
||||||
console.log("🔧 [SplitPanel] 수정 버튼 클릭 - groupByColumns 확인:", {
|
|
||||||
groupByColumns,
|
|
||||||
editButtonConfig: componentConfig.rightPanel?.editButton,
|
|
||||||
hasGroupByColumns: groupByColumns.length > 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
// ScreenModal 열기 이벤트 발생 (URL 파라미터로 ID + groupByColumns 전달)
|
// ScreenModal 열기 이벤트 발생 (URL 파라미터로 ID + groupByColumns 전달)
|
||||||
window.dispatchEvent(
|
window.dispatchEvent(
|
||||||
new CustomEvent("openScreenModal", {
|
new CustomEvent("openScreenModal", {
|
||||||
|
|
@ -2540,13 +2431,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("✅ [SplitPanel] openScreenModal 이벤트 발생:", {
|
|
||||||
screenId: modalScreenId,
|
|
||||||
editId: primaryKeyValue,
|
|
||||||
tableName: rightTableName,
|
|
||||||
groupByColumns: groupByColumns.length > 0 ? JSON.stringify(groupByColumns) : "없음",
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2606,8 +2490,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
cleanData.company_code = companyCode;
|
cleanData.company_code = companyCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("📝 [SplitPanel] 커스텀 우측 패널 저장:", { tableName, primaryKey, data: cleanData });
|
|
||||||
|
|
||||||
const response = await dataApi.updateRecord(tableName, primaryKey, cleanData);
|
const response = await dataApi.updateRecord(tableName, primaryKey, cleanData);
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
|
|
@ -2743,8 +2625,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log("📝 데이터 수정:", { tableName, primaryKey, data: editModalFormData });
|
|
||||||
|
|
||||||
// 프론트엔드 전용 필드 제거 (children, level 등)
|
// 프론트엔드 전용 필드 제거 (children, level 등)
|
||||||
const cleanData = { ...editModalFormData };
|
const cleanData = { ...editModalFormData };
|
||||||
delete cleanData.children;
|
delete cleanData.children;
|
||||||
|
|
@ -2761,7 +2641,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
rightColumn: componentConfig.rightPanel.relation.rightColumn,
|
rightColumn: componentConfig.rightPanel.relation.rightColumn,
|
||||||
oldLeftValue: editModalItem[componentConfig.rightPanel.relation.leftColumn],
|
oldLeftValue: editModalItem[componentConfig.rightPanel.relation.leftColumn],
|
||||||
};
|
};
|
||||||
console.log("🔗 조인 관계 정보 추가:", updatePayload._relationInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await dataApi.updateRecord(tableName, primaryKey, updatePayload);
|
const result = await dataApi.updateRecord(tableName, primaryKey, updatePayload);
|
||||||
|
|
@ -2831,7 +2710,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
// 우측 패널 + 중계 테이블 모드인 경우
|
// 우측 패널 + 중계 테이블 모드인 경우
|
||||||
if (deleteModalPanel === "right" && componentConfig.rightPanel?.addConfig?.targetTable) {
|
if (deleteModalPanel === "right" && componentConfig.rightPanel?.addConfig?.targetTable) {
|
||||||
tableName = componentConfig.rightPanel.addConfig.targetTable;
|
tableName = componentConfig.rightPanel.addConfig.targetTable;
|
||||||
console.log("🔗 중계 테이블 모드: 삭제 대상 테이블 =", tableName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2841,9 +2719,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
if (!primaryKey && deleteModalItem && typeof deleteModalItem === "object") {
|
if (!primaryKey && deleteModalItem && typeof deleteModalItem === "object") {
|
||||||
// id가 없는 경우에만 전체 객체 전달 (복합키 테이블)
|
// id가 없는 경우에만 전체 객체 전달 (복합키 테이블)
|
||||||
primaryKey = deleteModalItem;
|
primaryKey = deleteModalItem;
|
||||||
console.log("🔑 복합키: 전체 객체 전달", Object.keys(primaryKey));
|
|
||||||
} else {
|
|
||||||
console.log("🔑 단일키 삭제: id =", primaryKey, "테이블 =", tableName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tableName || !primaryKey) {
|
if (!tableName || !primaryKey) {
|
||||||
|
|
@ -2856,16 +2731,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log("🗑️ 데이터 삭제:", { tableName, primaryKey });
|
|
||||||
|
|
||||||
// 🔍 중복 제거 설정 디버깅
|
|
||||||
console.log("🔍 중복 제거 디버깅:", {
|
|
||||||
panel: deleteModalPanel,
|
|
||||||
dataFilter: componentConfig.rightPanel?.dataFilter,
|
|
||||||
deduplication: componentConfig.rightPanel?.dataFilter?.deduplication,
|
|
||||||
enabled: componentConfig.rightPanel?.dataFilter?.deduplication?.enabled,
|
|
||||||
});
|
|
||||||
|
|
||||||
let result;
|
let result;
|
||||||
|
|
||||||
// 🔧 중복 제거가 활성화된 경우, groupByColumn 기준으로 모든 관련 레코드 삭제
|
// 🔧 중복 제거가 활성화된 경우, groupByColumn 기준으로 모든 관련 레코드 삭제
|
||||||
|
|
@ -2875,7 +2740,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
|
|
||||||
if (groupByColumn && deleteModalItem[groupByColumn]) {
|
if (groupByColumn && deleteModalItem[groupByColumn]) {
|
||||||
const groupValue = deleteModalItem[groupByColumn];
|
const groupValue = deleteModalItem[groupByColumn];
|
||||||
console.log(`🔗 중복 제거 활성화: ${groupByColumn} = ${groupValue} 기준으로 모든 레코드 삭제`);
|
|
||||||
|
|
||||||
// groupByColumn 값으로 필터링하여 삭제
|
// groupByColumn 값으로 필터링하여 삭제
|
||||||
const filterConditions: Record<string, any> = {
|
const filterConditions: Record<string, any> = {
|
||||||
|
|
@ -2889,8 +2753,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
filterConditions[rightColumn] = selectedLeftItem[leftColumn];
|
filterConditions[rightColumn] = selectedLeftItem[leftColumn];
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("🗑️ 그룹 삭제 조건:", filterConditions);
|
|
||||||
|
|
||||||
// 그룹 삭제 API 호출
|
// 그룹 삭제 API 호출
|
||||||
result = await dataApi.deleteGroupRecords(tableName, filterConditions);
|
result = await dataApi.deleteGroupRecords(tableName, filterConditions);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -3022,7 +2884,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
if (addConfig.leftPanelColumn && addConfig.targetColumn && selectedLeftItem) {
|
if (addConfig.leftPanelColumn && addConfig.targetColumn && selectedLeftItem) {
|
||||||
const leftValue = selectedLeftItem[addConfig.leftPanelColumn];
|
const leftValue = selectedLeftItem[addConfig.leftPanelColumn];
|
||||||
finalData[addConfig.targetColumn] = leftValue;
|
finalData[addConfig.targetColumn] = leftValue;
|
||||||
console.log(`🔗 좌측 패널 값 자동 채움: ${addConfig.targetColumn} = ${leftValue}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 자동 채움 컬럼 추가
|
// 자동 채움 컬럼 추가
|
||||||
|
|
@ -3030,7 +2891,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
Object.entries(addConfig.autoFillColumns).forEach(([key, value]) => {
|
Object.entries(addConfig.autoFillColumns).forEach(([key, value]) => {
|
||||||
finalData[key] = value;
|
finalData[key] = value;
|
||||||
});
|
});
|
||||||
console.log("🔧 자동 채움 컬럼:", addConfig.autoFillColumns);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 일반 테이블 모드
|
// 일반 테이블 모드
|
||||||
|
|
@ -3066,8 +2926,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log("📝 데이터 추가:", { tableName, data: finalData });
|
|
||||||
|
|
||||||
const result = await dataApi.createRecord(tableName, finalData);
|
const result = await dataApi.createRecord(tableName, finalData);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
|
|
@ -3210,7 +3068,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleRefreshTable = () => {
|
const handleRefreshTable = () => {
|
||||||
if (!isDesignMode) {
|
if (!isDesignMode) {
|
||||||
console.log("🔄 [SplitPanel] refreshTable 이벤트 수신 - 데이터 새로고침");
|
|
||||||
loadLeftData();
|
loadLeftData();
|
||||||
// 현재 활성 탭 데이터 새로고침 (좌측 미선택 시에도 전체 데이터 로드)
|
// 현재 활성 탭 데이터 새로고침 (좌측 미선택 시에도 전체 데이터 로드)
|
||||||
if (activeTabIndex === 0) {
|
if (activeTabIndex === 0) {
|
||||||
|
|
@ -3510,7 +3367,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
}}
|
}}
|
||||||
// 🆕 중첩된 탭 내부 컴포넌트 선택 핸들러 - 부모 분할 패널 정보 포함
|
// 🆕 중첩된 탭 내부 컴포넌트 선택 핸들러 - 부모 분할 패널 정보 포함
|
||||||
onSelectTabComponent={(tabId: string, compId: string, tabComp: any) => {
|
onSelectTabComponent={(tabId: string, compId: string, tabComp: any) => {
|
||||||
console.log("🔍 [SplitPanel-Left] onSelectTabComponent 호출:", { tabId, compId, tabComp, parentSplitPanelId: component.id });
|
|
||||||
// 탭 내 컴포넌트 선택 상태 업데이트
|
// 탭 내 컴포넌트 선택 상태 업데이트
|
||||||
setNestedTabSelectedCompId(compId);
|
setNestedTabSelectedCompId(compId);
|
||||||
// 부모 분할 패널 정보와 함께 전역 이벤트 발생
|
// 부모 분할 패널 정보와 함께 전역 이벤트 발생
|
||||||
|
|
@ -3606,12 +3462,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
(() => {
|
(() => {
|
||||||
// 🆕 그룹별 합산된 데이터 사용
|
// 🆕 그룹별 합산된 데이터 사용
|
||||||
const dataSource = summedLeftData;
|
const dataSource = summedLeftData;
|
||||||
console.log(
|
|
||||||
"🔍 [테이블모드 렌더링] dataSource 개수:",
|
|
||||||
dataSource.length,
|
|
||||||
"leftGroupSumConfig:",
|
|
||||||
leftGroupSumConfig,
|
|
||||||
);
|
|
||||||
|
|
||||||
// 🔧 로컬 검색 필터 적용
|
// 🔧 로컬 검색 필터 적용
|
||||||
const filteredData = leftSearchQuery
|
const filteredData = leftSearchQuery
|
||||||
|
|
@ -3898,12 +3748,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
(() => {
|
(() => {
|
||||||
// 🆕 그룹별 합산된 데이터 사용
|
// 🆕 그룹별 합산된 데이터 사용
|
||||||
const dataToDisplay = summedLeftData;
|
const dataToDisplay = summedLeftData;
|
||||||
console.log(
|
|
||||||
"🔍 [렌더링] dataToDisplay 개수:",
|
|
||||||
dataToDisplay.length,
|
|
||||||
"leftGroupSumConfig:",
|
|
||||||
leftGroupSumConfig,
|
|
||||||
);
|
|
||||||
|
|
||||||
// 검색 필터링 (클라이언트 사이드)
|
// 검색 필터링 (클라이언트 사이드)
|
||||||
const filteredLeftData = leftSearchQuery
|
const filteredLeftData = leftSearchQuery
|
||||||
|
|
@ -3930,13 +3774,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
const configuredColumns = componentConfig.leftPanel?.columns || [];
|
const configuredColumns = componentConfig.leftPanel?.columns || [];
|
||||||
let displayFields: { label: string; value: any }[] = [];
|
let displayFields: { label: string; value: any }[] = [];
|
||||||
|
|
||||||
// 디버그 로그
|
|
||||||
if (index === 0) {
|
|
||||||
console.log("🔍 좌측 패널 표시 로직:");
|
|
||||||
console.log(" - 설정된 표시 컬럼:", configuredColumns);
|
|
||||||
console.log(" - item keys:", Object.keys(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configuredColumns.length > 0) {
|
if (configuredColumns.length > 0) {
|
||||||
// 🔧 "표시할 컬럼 선택"에서 설정한 컬럼 사용
|
// 🔧 "표시할 컬럼 선택"에서 설정한 컬럼 사용
|
||||||
displayFields = configuredColumns.slice(0, 2).map((col: any) => {
|
displayFields = configuredColumns.slice(0, 2).map((col: any) => {
|
||||||
|
|
@ -3960,10 +3797,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
value: displayValue,
|
value: displayValue,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
if (index === 0) {
|
|
||||||
console.log(" ✅ 설정된 컬럼 기반 표시:", displayFields);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// 설정된 컬럼이 없으면 자동으로 첫 2개 필드 표시
|
// 설정된 컬럼이 없으면 자동으로 첫 2개 필드 표시
|
||||||
const keys = Object.keys(item).filter(
|
const keys = Object.keys(item).filter(
|
||||||
|
|
@ -3984,10 +3817,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
value: displayValue,
|
value: displayValue,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
if (index === 0) {
|
|
||||||
console.log(" ⚠️ 설정된 컬럼 없음, 자동 선택:", displayFields);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const displayTitle = displayFields[0]?.value || item.name || item.title || `항목 ${index + 1}`;
|
const displayTitle = displayFields[0]?.value || item.name || item.title || `항목 ${index + 1}`;
|
||||||
|
|
@ -4801,7 +4630,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
_isKeyColumn: true, // 구분용 플래그
|
_isKeyColumn: true, // 구분용 플래그
|
||||||
}));
|
}));
|
||||||
columnsToShow = [...keyColsToAdd, ...columnsToShow];
|
columnsToShow = [...keyColsToAdd, ...columnsToShow];
|
||||||
console.log("🔗 [우측패널] 그룹모드 - 키 컬럼 추가:", missingKeyColumns);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -5120,39 +4948,24 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
let displayEntries: [string, any, string][] = [];
|
let displayEntries: [string, any, string][] = [];
|
||||||
|
|
||||||
if (rightColumns && rightColumns.length > 0) {
|
if (rightColumns && rightColumns.length > 0) {
|
||||||
console.log("🔍 [디버깅] 상세 모드 표시 로직:");
|
|
||||||
console.log(" 📋 rightData 전체:", rightData);
|
|
||||||
console.log(" 📋 rightData keys:", Object.keys(rightData));
|
|
||||||
console.log(
|
|
||||||
" ⚙️ 설정된 컬럼:",
|
|
||||||
rightColumns.map((c) => `${c.name} (${c.label})`),
|
|
||||||
);
|
|
||||||
|
|
||||||
// 설정된 컬럼만 표시 (showInDetail이 false가 아닌 것만)
|
// 설정된 컬럼만 표시 (showInDetail이 false가 아닌 것만)
|
||||||
displayEntries = rightColumns
|
displayEntries = rightColumns
|
||||||
.filter((col) => col.showInDetail !== false)
|
.filter((col) => col.showInDetail !== false)
|
||||||
.map((col) => {
|
.map((col) => {
|
||||||
// 🆕 엔티티 조인 컬럼 처리 (예: item_info.item_name → item_name)
|
|
||||||
let value = rightData[col.name];
|
let value = rightData[col.name];
|
||||||
console.log(` 🔎 컬럼 "${col.name}": 직접 접근 = ${value}`);
|
|
||||||
|
|
||||||
if (value === undefined && col.name.includes(".")) {
|
if (value === undefined && col.name.includes(".")) {
|
||||||
const columnName = col.name.split(".").pop();
|
const columnName = col.name.split(".").pop();
|
||||||
value = rightData[columnName || ""];
|
value = rightData[columnName || ""];
|
||||||
console.log(` → 변환 후 "${columnName}" 접근 = ${value}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [col.name, value, col.label] as [string, any, string];
|
return [col.name, value, col.label] as [string, any, string];
|
||||||
})
|
});
|
||||||
; // 설정된 컬럼은 null/empty여도 항상 표시
|
|
||||||
|
|
||||||
console.log(" ✅ 최종 표시할 항목:", displayEntries.length, "개");
|
|
||||||
} else {
|
} else {
|
||||||
// 설정 없으면 모든 컬럼 표시
|
// 설정 없으면 모든 컬럼 표시
|
||||||
displayEntries = Object.entries(rightData)
|
displayEntries = Object.entries(rightData)
|
||||||
.filter(([_, value]) => value !== null && value !== undefined && value !== "")
|
.filter(([_, value]) => value !== null && value !== undefined && value !== "")
|
||||||
.map(([key, value]) => [key, value, ""] as [string, any, string]);
|
.map(([key, value]) => [key, value, ""] as [string, any, string]);
|
||||||
console.log(" ⚠️ 컬럼 설정 없음, 모든 컬럼 표시");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasDetailEditButton = !isDesignMode && (componentConfig.rightPanel?.editButton?.enabled ?? true);
|
const hasDetailEditButton = !isDesignMode && (componentConfig.rightPanel?.editButton?.enabled ?? true);
|
||||||
|
|
|
||||||
|
|
@ -381,6 +381,7 @@ export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
|
||||||
onEditSave?.();
|
onEditSave?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// category/code 타입: select는 반드시 h-8(32px)로 행 높이 유지
|
||||||
if (hasCategoryOptions) {
|
if (hasCategoryOptions) {
|
||||||
const selectOptions = Object.entries(categoryOptions).map(([value, info]) => ({
|
const selectOptions = Object.entries(categoryOptions).map(([value, info]) => ({
|
||||||
value,
|
value,
|
||||||
|
|
@ -393,7 +394,7 @@ export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
|
||||||
onChange={(e) => onEditingValueChange?.(e.target.value)}
|
onChange={(e) => onEditingValueChange?.(e.target.value)}
|
||||||
onKeyDown={onEditKeyDown}
|
onKeyDown={onEditKeyDown}
|
||||||
onBlur={handleBlurSave}
|
onBlur={handleBlurSave}
|
||||||
className={commonInputClass}
|
className={cn(commonInputClass, "h-8")}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
<option value="">선택하세요</option>
|
<option value="">선택하세요</option>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue