Merge pull request 'feat/screenDesinger' (#196) from feat/screenDesinger into main

Reviewed-on: http://39.117.244.52:3000/kjs/ERP-node/pulls/196
This commit is contained in:
hyeonsu 2025-11-10 11:57:32 +09:00
commit 4b540dc587
2 changed files with 69 additions and 17 deletions

View File

@ -160,6 +160,16 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
// searchTerm 제거 - 클라이언트 사이드에서 필터링 // searchTerm 제거 - 클라이언트 사이드에서 필터링
}); });
// 가나다순 정렬 (좌측 패널의 표시 컬럼 기준)
const leftColumn = componentConfig.rightPanel?.relation?.leftColumn;
if (leftColumn && result.data.length > 0) {
result.data.sort((a, b) => {
const aValue = String(a[leftColumn] || '');
const bValue = String(b[leftColumn] || '');
return aValue.localeCompare(bValue, 'ko-KR');
});
}
// 계층 구조 빌드 // 계층 구조 빌드
const hierarchicalData = buildHierarchy(result.data); const hierarchicalData = buildHierarchy(result.data);
setLeftData(hierarchicalData); setLeftData(hierarchicalData);
@ -173,7 +183,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
} finally { } finally {
setIsLoadingLeft(false); setIsLoadingLeft(false);
} }
}, [componentConfig.leftPanel?.tableName, isDesignMode, toast, buildHierarchy]); }, [componentConfig.leftPanel?.tableName, componentConfig.rightPanel?.relation?.leftColumn, isDesignMode, toast, buildHierarchy]);
// 우측 데이터 로드 // 우측 데이터 로드
const loadRightData = useCallback( const loadRightData = useCallback(
@ -293,9 +303,19 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
// 추가 버튼 핸들러 // 추가 버튼 핸들러
const handleAddClick = useCallback((panel: "left" | "right") => { const handleAddClick = useCallback((panel: "left" | "right") => {
setAddModalPanel(panel); setAddModalPanel(panel);
setAddModalFormData({});
// 우측 패널 추가 시, 좌측에서 선택된 항목의 조인 컬럼 값을 자동으로 채움
if (panel === "right" && selectedLeftItem && componentConfig.leftPanel?.leftColumn && componentConfig.rightPanel?.rightColumn) {
const leftColumnValue = selectedLeftItem[componentConfig.leftPanel.leftColumn];
setAddModalFormData({
[componentConfig.rightPanel.rightColumn]: leftColumnValue
});
} else {
setAddModalFormData({});
}
setShowAddModal(true); setShowAddModal(true);
}, []); }, [selectedLeftItem, componentConfig]);
// 수정 버튼 핸들러 // 수정 버튼 핸들러
const handleEditClick = useCallback((panel: "left" | "right", item: any) => { const handleEditClick = useCallback((panel: "left" | "right", item: any) => {
@ -1316,10 +1336,17 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
return modalColumns?.map((col, index) => { return modalColumns?.map((col, index) => {
// 항목별 추가 버튼으로 열렸을 때, parentColumn은 미리 채워져 있고 수정 불가 // 항목별 추가 버튼으로 열렸을 때, parentColumn은 미리 채워져 있고 수정 불가
const isPreFilled = addModalPanel === "left-item" const isItemAddPreFilled = addModalPanel === "left-item"
&& componentConfig.leftPanel?.itemAddConfig?.parentColumn === col.name && componentConfig.leftPanel?.itemAddConfig?.parentColumn === col.name
&& addModalFormData[col.name]; && addModalFormData[col.name];
// 우측 패널 추가 시, 조인 컬럼(rightColumn)은 미리 채워져 있고 수정 불가
const isRightJoinPreFilled = addModalPanel === "right"
&& componentConfig.rightPanel?.rightColumn === col.name
&& addModalFormData[col.name];
const isPreFilled = isItemAddPreFilled || isRightJoinPreFilled;
return ( return (
<div key={index}> <div key={index}>
<Label htmlFor={col.name} className="text-xs sm:text-sm"> <Label htmlFor={col.name} className="text-xs sm:text-sm">

View File

@ -9,6 +9,7 @@ import { Slider } from "@/components/ui/slider";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from "@/components/ui/command"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from "@/components/ui/command";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
import { Check, ChevronsUpDown, ArrowRight, Plus, X } from "lucide-react"; import { Check, ChevronsUpDown, ArrowRight, Plus, X } from "lucide-react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { SplitPanelLayoutConfig } from "./types"; import { SplitPanelLayoutConfig } from "./types";
@ -284,7 +285,7 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
console.log(" - availableRightTables:", availableRightTables.length, "개"); console.log(" - availableRightTables:", availableRightTables.length, "개");
return ( return (
<div className="space-y-6"> <div className="space-y-4">
{/* 관계 타입 선택 */} {/* 관계 타입 선택 */}
<div className="space-y-3"> <div className="space-y-3">
<h3 className="text-sm font-semibold"> </h3> <h3 className="text-sm font-semibold"> </h3>
@ -324,9 +325,14 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
</Select> </Select>
</div> </div>
{/* 좌측 패널 설정 (마스터) */} {/* 좌측 패널 설정 (Accordion) */}
<div className="space-y-4"> <Accordion type="single" collapsible defaultValue="left-panel" className="w-full">
<h3 className="text-sm font-semibold"> ()</h3> <AccordionItem value="left-panel" className="border rounded-lg px-4">
<AccordionTrigger className="text-sm font-semibold hover:no-underline">
()
</AccordionTrigger>
<AccordionContent className="overflow-visible">
<div className="space-y-4 pt-2">
<div className="space-y-2"> <div className="space-y-2">
<Label> </Label> <Label> </Label>
@ -807,11 +813,19 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
</div> </div>
</div> </div>
)} )}
</div> </div>
</AccordionContent>
</AccordionItem>
</Accordion>
{/* 우측 패널 설정 */} {/* 우측 패널 설정 (Accordion) */}
<div className="space-y-4"> <Accordion type="single" collapsible defaultValue="right-panel" className="w-full">
<h3 className="text-sm font-semibold"> ({relationshipType === "detail" ? "상세" : "조인"})</h3> <AccordionItem value="right-panel" className="border rounded-lg px-4">
<AccordionTrigger className="text-sm font-semibold hover:no-underline">
({relationshipType === "detail" ? "상세" : "조인"})
</AccordionTrigger>
<AccordionContent className="overflow-visible">
<div className="space-y-4 pt-2">
<div className="space-y-2"> <div className="space-y-2">
<Label> </Label> <Label> </Label>
@ -1357,11 +1371,19 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
</div> </div>
</div> </div>
)} )}
</div> </div>
</AccordionContent>
</AccordionItem>
</Accordion>
{/* 레이아웃 설정 */} {/* 레이아웃 설정 (Accordion) */}
<div className="space-y-4"> <Accordion type="single" collapsible className="w-full">
<h3 className="text-sm font-semibold"> </h3> <AccordionItem value="layout" className="border rounded-lg px-4">
<AccordionTrigger className="text-sm font-semibold hover:no-underline">
</AccordionTrigger>
<AccordionContent className="overflow-visible">
<div className="space-y-4 pt-2">
<div className="space-y-2"> <div className="space-y-2">
<Label> : {config.splitRatio || 30}%</Label> <Label> : {config.splitRatio || 30}%</Label>
@ -1389,7 +1411,10 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
onCheckedChange={(checked) => updateConfig({ autoLoad: checked })} onCheckedChange={(checked) => updateConfig({ autoLoad: checked })}
/> />
</div> </div>
</div> </div>
</AccordionContent>
</AccordionItem>
</Accordion>
</div> </div>
); );
}; };