Merge branch 'gbpark-node' of http://39.117.244.52:3000/kjs/ERP-node into jskim-node

This commit is contained in:
kjs
2026-03-11 12:23:52 +09:00
588 changed files with 25062 additions and 13798 deletions

View File

@@ -492,24 +492,22 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
return `${height}px`; // 숫자면 px 추가
};
const componentStyle: React.CSSProperties = isPreview
const componentStyle: React.CSSProperties = isDesignMode
? {
// 반응형 모드: position relative, 그리드 컨테이너가 제공하는 크기 사용
position: "relative",
width: "100%", // 🆕 부모 컨테이너 너비에 맞춤
height: getHeightValue(),
border: "1px solid #e5e7eb",
}
: {
// 디자이너 모드: position absolute
position: "absolute",
left: `${component.style?.positionX || 0}px`,
top: `${component.style?.positionY || 0}px`,
width: "100%", // 🆕 부모 컨테이너 너비에 맞춤 (그리드 기반)
width: "100%",
height: getHeightValue(),
zIndex: component.style?.positionZ || 1,
cursor: isDesignMode ? "pointer" : "default",
cursor: "pointer",
border: isSelected ? "2px solid #3b82f6" : "1px solid #e5e7eb",
}
: {
position: "relative",
width: "100%",
height: "100%",
border: "1px solid #e5e7eb",
};
// 계층 구조 빌드 함수 (트리 구조 유지)
@@ -2491,13 +2489,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
<div
ref={containerRef}
style={{
...(isPreview
? {
position: "relative",
height: `${component.style?.height || 600}px`,
border: "1px solid #e5e7eb",
}
: componentStyle),
...componentStyle,
display: "flex",
flexDirection: "row",
}}
@@ -2511,7 +2503,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
>
{/* 좌측 패널 */}
<div
style={{ width: `${leftWidth}%`, minWidth: isPreview ? "0" : `${minLeftWidth}px`, height: "100%" }}
style={{ width: `${leftWidth}%`, minWidth: isDesignMode ? `${minLeftWidth}px` : "0", height: "100%" }}
className="border-border flex flex-shrink-0 flex-col border-r"
>
<Card className="flex flex-col border-0 shadow-none" style={{ height: "100%" }}>
@@ -2558,21 +2550,21 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
{isDesignMode ? (
// 디자인 모드: 샘플 테이블
<div className="overflow-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<table className="min-w-full divide-y divide-border">
<thead className="bg-muted">
<tr>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase"> 1</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase"> 2</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase"> 3</th>
<th className="px-3 py-2 text-left text-xs font-medium text-muted-foreground uppercase"> 1</th>
<th className="px-3 py-2 text-left text-xs font-medium text-muted-foreground uppercase"> 2</th>
<th className="px-3 py-2 text-left text-xs font-medium text-muted-foreground uppercase"> 3</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 bg-white">
<tr className="cursor-pointer hover:bg-gray-50">
<tbody className="divide-y divide-border bg-white">
<tr className="cursor-pointer hover:bg-muted">
<td className="px-3 py-2 text-sm whitespace-nowrap"> 1-1</td>
<td className="px-3 py-2 text-sm whitespace-nowrap"> 1-2</td>
<td className="px-3 py-2 text-sm whitespace-nowrap"> 1-3</td>
</tr>
<tr className="cursor-pointer hover:bg-gray-50">
<tr className="cursor-pointer hover:bg-muted">
<td className="px-3 py-2 text-sm whitespace-nowrap"> 2-1</td>
<td className="px-3 py-2 text-sm whitespace-nowrap"> 2-2</td>
<td className="px-3 py-2 text-sm whitespace-nowrap"> 2-3</td>
@@ -2638,16 +2630,16 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
<div className="overflow-auto">
{groupedLeftData.map((group, groupIdx) => (
<div key={groupIdx} className="mb-4">
<div className="bg-gray-100 px-3 py-2 text-sm font-semibold">
<div className="bg-muted px-3 py-2 text-sm font-semibold">
{group.groupKey} ({group.count})
</div>
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<table className="min-w-full divide-y divide-border">
<thead className="bg-muted">
<tr>
{columnsToShow.map((col, idx) => (
<th
key={idx}
className="px-3 py-2 text-left text-xs font-medium tracking-wider text-gray-500 uppercase"
className="px-3 py-2 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase"
style={{
width: col.width ? `${col.width}px` : "auto",
textAlign: col.align || "left",
@@ -2658,7 +2650,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
))}
</tr>
</thead>
<tbody className="divide-y divide-gray-200 bg-white">
<tbody className="divide-y divide-border bg-white">
{group.items.map((item, idx) => {
const sourceColumn = componentConfig.leftPanel?.itemAddConfig?.sourceColumn || "id";
const itemId = item[sourceColumn] || item.id || item.ID;
@@ -2677,7 +2669,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
{columnsToShow.map((col, colIdx) => (
<td
key={colIdx}
className="px-3 py-2 text-sm whitespace-nowrap text-gray-900"
className="px-3 py-2 text-sm whitespace-nowrap text-foreground"
style={{ textAlign: col.align || "left" }}
>
{formatCellValue(
@@ -2702,13 +2694,13 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
// 🔧 일반 테이블 렌더링 (그룹화 없음)
return (
<div className="overflow-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="sticky top-0 z-10 bg-gray-50">
<table className="min-w-full divide-y divide-border">
<thead className="sticky top-0 z-10 bg-muted">
<tr>
{columnsToShow.map((col, idx) => (
<th
key={idx}
className="px-3 py-2 text-left text-xs font-medium tracking-wider text-gray-500 uppercase"
className="px-3 py-2 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase"
style={{
width: col.width ? `${col.width}px` : "auto",
minWidth: "80px",
@@ -2720,7 +2712,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
))}
</tr>
</thead>
<tbody className="divide-y divide-gray-200 bg-white">
<tbody className="divide-y divide-border bg-white">
{filteredData.map((item, idx) => {
const sourceColumn = componentConfig.leftPanel?.itemAddConfig?.sourceColumn || "id";
const itemId = item[sourceColumn] || item.id || item.ID;
@@ -2739,7 +2731,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
{columnsToShow.map((col, colIdx) => (
<td
key={colIdx}
className="px-3 py-2 text-sm whitespace-nowrap text-gray-900"
className="px-3 py-2 text-sm whitespace-nowrap text-foreground"
style={{ textAlign: col.align || "left" }}
>
{formatCellValue(
@@ -2898,9 +2890,9 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
{hasChildren ? (
<div className="flex-shrink-0">
{isExpanded ? (
<ChevronDown className="h-4 w-4 text-gray-500" />
<ChevronDown className="h-4 w-4 text-muted-foreground" />
) : (
<ChevronRight className="h-4 w-4 text-gray-500" />
<ChevronRight className="h-4 w-4 text-muted-foreground" />
)}
</div>
) : (
@@ -2924,10 +2916,10 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
e.stopPropagation();
handleEditClick("left", item);
}}
className="rounded p-1 transition-colors hover:bg-gray-200"
className="rounded p-1 transition-colors hover:bg-muted/80"
title="수정"
>
<Pencil className="h-4 w-4 text-gray-600" />
<Pencil className="h-4 w-4 text-muted-foreground" />
</button>
{/* 삭제 버튼 */}
@@ -2936,10 +2928,10 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
e.stopPropagation();
handleDeleteClick("left", item);
}}
className="rounded p-1 transition-colors hover:bg-red-100"
className="rounded p-1 transition-colors hover:bg-destructive/10"
title="삭제"
>
<Trash2 className="h-4 w-4 text-red-600" />
<Trash2 className="h-4 w-4 text-destructive" />
</button>
{/* 항목별 추가 버튼 */}
@@ -2949,10 +2941,10 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
e.stopPropagation();
handleItemAddClick(item);
}}
className="rounded p-1 transition-colors hover:bg-gray-200"
className="rounded p-1 transition-colors hover:bg-muted/80"
title="하위 항목 추가"
>
<Plus className="h-4 w-4 text-gray-600" />
<Plus className="h-4 w-4 text-muted-foreground" />
</button>
)}
</div>
@@ -3004,7 +2996,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
{/* 우측 패널 */}
<div
style={{ width: `${100 - leftWidth}%`, minWidth: isPreview ? "0" : `${minRightWidth}px`, height: "100%" }}
style={{ width: `${100 - leftWidth}%`, minWidth: isDesignMode ? `${minRightWidth}px` : "0", height: "100%" }}
className="flex flex-shrink-0 flex-col"
>
<Card className="flex flex-col border-0 shadow-none" style={{ height: "100%" }}>
@@ -3185,7 +3177,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
<Button
variant="ghost"
size="sm"
className="h-7 w-7 p-0 text-red-500 hover:text-red-600"
className="h-7 w-7 p-0 text-destructive hover:text-destructive"
onClick={() => handleDeleteClick("right", item)}
>
<Trash2 className="h-3.5 w-3.5" />
@@ -3262,7 +3254,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
<Button
variant="ghost"
size="sm"
className="h-7 w-7 p-0 text-red-500 hover:text-red-600"
className="h-7 w-7 p-0 text-destructive hover:text-destructive"
onClick={(e) => {
e.stopPropagation();
handleDeleteClick("right", item);
@@ -3273,9 +3265,9 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
)}
{detailColumns.length > 0 &&
(isExpanded ? (
<ChevronUp className="h-4 w-4 text-gray-400" />
<ChevronUp className="h-4 w-4 text-muted-foreground/70" />
) : (
<ChevronDown className="h-4 w-4 text-gray-400" />
<ChevronDown className="h-4 w-4 text-muted-foreground/70" />
))}
</div>
</div>
@@ -3388,13 +3380,13 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
)}
</div>
<div className="overflow-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="sticky top-0 z-10 bg-gray-50">
<table className="min-w-full divide-y divide-border">
<thead className="sticky top-0 z-10 bg-muted">
<tr>
{columnsToShow.map((col, idx) => (
<th
key={idx}
className="px-3 py-2 text-left text-xs font-medium tracking-wider text-gray-500 uppercase"
className="px-3 py-2 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase"
style={{
width: col.width ? `${col.width}px` : "auto",
textAlign: col.align || "left",
@@ -3407,13 +3399,13 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
{!isDesignMode &&
((componentConfig.rightPanel?.editButton?.enabled ?? true) ||
(componentConfig.rightPanel?.deleteButton?.enabled ?? true)) && (
<th className="px-3 py-2 text-right text-xs font-medium text-gray-500 uppercase">
<th className="px-3 py-2 text-right text-xs font-medium text-muted-foreground uppercase">
</th>
)}
</tr>
</thead>
<tbody className="divide-y divide-gray-200 bg-white">
<tbody className="divide-y divide-border bg-white">
{filteredData.map((item, idx) => {
const itemId = item.id || item.ID;
@@ -3422,7 +3414,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
{columnsToShow.map((col, colIdx) => (
<td
key={colIdx}
className="px-3 py-2 text-sm whitespace-nowrap text-gray-900"
className="px-3 py-2 text-sm whitespace-nowrap text-foreground"
style={{ textAlign: col.align || "left" }}
>
{formatCellValue(
@@ -3461,10 +3453,10 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
e.stopPropagation();
handleDeleteClick("right", item);
}}
className="rounded p-1 transition-colors hover:bg-red-100"
className="rounded p-1 transition-colors hover:bg-destructive/10"
title={componentConfig.rightPanel?.deleteButton?.buttonLabel || "삭제"}
>
<Trash2 className="h-4 w-4 text-red-600" />
<Trash2 className="h-4 w-4 text-destructive" />
</button>
)}
</div>
@@ -3594,16 +3586,16 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
e.stopPropagation();
handleDeleteClick("right", item);
}}
className="rounded p-1 transition-colors hover:bg-red-100"
className="rounded p-1 transition-colors hover:bg-destructive/10"
title={componentConfig.rightPanel?.deleteButton?.buttonLabel || "삭제"}
>
<Trash2 className="h-4 w-4 text-red-600" />
<Trash2 className="h-4 w-4 text-destructive" />
</button>
)}
{/* 확장/접기 버튼 */}
<button
onClick={() => toggleRightItemExpansion(itemId)}
className="rounded p-1 transition-colors hover:bg-gray-200"
className="rounded p-1 transition-colors hover:bg-muted/80"
>
{isExpanded ? (
<ChevronUp className="text-muted-foreground h-5 w-5" />
@@ -3808,7 +3800,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
<div key={index}>
<Label htmlFor={col.name} className="text-xs sm:text-sm">
{col.label} {col.required && <span className="text-destructive">*</span>}
{isPreFilled && <span className="ml-2 text-[10px] text-blue-600">( )</span>}
{isPreFilled && <span className="ml-2 text-[10px] text-primary">( )</span>}
</Label>
<Input
id={col.name}